How to use $geoNear with embedded GeoJsonPoint field? - mongodb

I have a collection for places with the following fields:
{
"name":"AAAAA",
.
.
"location" : {
"loc" : {
"type" : "Point",
"coordinates" : [
25.381911,
37.109551
]
}
.
.
}
}
I want to use aggregation with geoNear and I cannot find a way to set the field for the location. With a query like this:
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },
distanceField: "dist",
maxDistance: 2,
query: {
"categories.categoryList":"Cocktail Bar"
},
includeLocs: "location.loc",
num: 5,
spherical: true
}
}]);
I get this error:
"errmsg" : "exception: geoNear command failed: { ok: 0.0, errmsg: \"no geo indices for geoNear\" }"
I think the problem is that the "loc" field is embedded in the location document and I cannot "tell" mongo to search near "location.loc".

The solution finally was to not include the GeoJsonPoint in the embedded location document. I just used "loc" in the same way as name and MongoDB "understood" that there were coordinates in the document.

Related

What is the correct way to query this document? (If the index is correct)

I've a BigChainDB docker container running in my machine and I'm trying to store and retrieve geospatial data.
I've created through the MongoDB interface a 2dsphere index "location" in the "metadata" collection.
I've checked with the command:
db.people.getIndexes()
And I think that everything it's ok, in fact the result is this:
{
"v" : 2,
"key" : {
"loc" : "2dsphere"
},
"name" : "loc_2dsphere",
"ns" : "bigchain.metadata",
"2dsphereIndexVersion" : 3
}
The document that I've inserted to try some spatial queries is (this is the result of a db.metadata.findOne() query):
{
"_id" : ObjectId("5ccab10a2ce1b70022823a0f"),
"id" : "752ee9abccf83c7fd25d86c9a7d12229ae292fa27544f6881f1dbf97ccd8b413",
"metadata" : {
"location" : {
"type" : "Point",
"coordinates" : [
22.170872,
113.578749
]
}
}
}
But when I use this spatial query nothing is retrieved:
db.metadata.find(
{
"metadata": {
"location": {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 22 , 113 ]
},
}
}
}
})
I'm doing anything wrong, or is there the possibility that the index doesn't work?
There are a couple of issues here.
The first is that the index is on the field loc whereas your query is querying metadata.location.
If you try creating a 2dsphere index on metadata.location you will see the 2nd error:
"errmsg" : "invalid point in geo near query $geometry argument: { type: \"Point\", coordinates: [ 22.0, 113.0 ] } longitude/latitude is out of bounds, lng: 22 lat: 113",
This error shows that the GEOJSON point defined in your document is invalid, as the latitude value of 113 is outside the acceptable range of [-90, 90].
You would need to correct the data to be valid GEOJSON before indexing.

$near operator on a nested object list item

I have mongo db with a collection of objects with a nested object list (events) like this:
{
"_id" : ObjectId("59db84093f2fba2bf0bcfa90"),
"progressStatus" : "NOT_STARTED",
"events" : [
{
"issueDate" : ISODate("2017-10-09T00:00:00.000Z"),
"eventType" : "xyz",
"location" : {
"point" : {
"type" : "Point",
"coordinates" : [
25.6011977000001,
45.6579755
]
}
},
"cancelled" : false,
}
]
}
Trying to make a query using $near or $nearSphere operator on events.$.location:
{
"events":{
"$elemMatch":{
"eventType":"xyz",
"$and":[
{
"cancelled":false
},
{
"location.point":{
"$nearSphere":{
"$geometry":{
type:"Point",
coordinates:[
25.601198,
45.657976
]
},
"$maxDistance":20.4
}
}
}
]
}
}
}
This query gives me an error:
Error: error: {
"waitedMS" : NumberLong(0),
"ok" : 0,
"errmsg" : "geoNear must be top-level expr",
"code" : 2
}
How should it be done?
neptune, this happens because geospatial queries with $nearSphere uses geoNear command to fetch documents, and the geoNear expression (when the command is run) needs to be at the top level on query. In your example, it happens to be at low levels (within elemMatch), raising an error when constructing the call to geoNear.
As I understand, your 2dsphere index is on "events.location.point", right ?
So, you can make this query like:
db.sample6.find({"events": {$elemMatch: {$and: [{eventType: "xyz"},{cancelled: false}]}}, "events.location.point": {"$nearSphere": {"$geometry": {type: "Point", coordinates: [25.601198, 45.657976]}, "$maxDistance": 20.4}}})
or just
db.sample6.find({"events.eventType": "xyz", "events.cancelled": false, "events.location.point": {"$nearSphere": {"$geometry": {type: "Point", coordinates: [25.601198, 45.657976]}, "$maxDistance": 20.4}}})
This last one I think is more wise, since it has already AND behaviour, without the need of $and use. Also, if it's possible, it would be cleaner and less confusing (since these queries have a lot of brackets and parentheses) to construct the geospatial info right on "location" field (if it only contains the coordinates).

Not getting results from $geoNear aggregate

Can you help me figure out why this query isn't returning results?
I imported a shape file using ogr2ogr to convert it to geoJson, then imported it to Mongo using this command:
"mongoimport --db ht--collection facilities< f.json"
Then, I created index like this: "db.facilities.ensureIndex({"geometry":"2dsphere"})"
Here's a sample document, along with the query that isn't returning anything and the index:
db.epa_facilities.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -74.501340, 39.944520 ] },
distanceField: "dist.calculated",
maxDistance: 3,
query: { type: "public" },
includeLocs: "dist.location",
spherical: true,
distanceMultiplier: 3959
}
}
])
Here's the document (properties removed for brevity):
{
"_id" : ObjectId("54ff20a90e46de508d1dae93"),
"type" : "Feature",
"properties" : {
… },
"geometry" : {
"type" : "Point",
"coordinates" : [
-74.50134,
39.9445200009289
]
}
}
And here's the index. I tried with both "geometry" and with "geometry.coordinates" with the same result:
{
"geometry.coordinates" : "2dsphere"
}
When you execute geoNear, in addition to the location filter, the query filter is also applied. Your query filter is { type: "public" } if none of the documents that satisfy $geoNear are of type "public" then you will get no documents as a result.

MongoDB: Using $geoIntersects or $geoWithin with $near in one query

I would like to query for all documents that have a polygon that a point is contained in and then for that result set, order it based on closeness of that point to the location of the document.
So imagine I have a database of friends because I'm just that cool, and would like to see which friends are within the my range and would be willing to come play. (each friend has a play-date polygon which is the range they are willing to travel for a play-date)
For all matches I would like to them proceed to see which friend I should call to come based on his actual address and its distance to my point (which is my address) so that I can determine if I am ok with them coming from far away. (lets say 300 meters)
So far I have below a query to find polygons that my point is contained within but I do not know how to include the $near operator of mongodb
For JSON:
{
"_id" : "objid",
"FRIEND_NAME" : "Bobby",
"GEOMETRY" : {
"type":"Polygon",
"coordinates":[[
[-73.98779153823898,40.718233223261],
[-74.004946447098,40.723575517498],
[-74.006771211624,40.730592217474],
[-73.99010896682698,40.746712376146],
[-73.973135948181,40.73974615047701],
[-73.975120782852,40.736128627654],
[-73.973997695541,40.730787341083],
[-73.983317613602,40.716639396436],
[-73.98779153823898,40.718233223261]
]]},
"FRIEND_POSITON" : {"lon" : -73.992188, "lat" : 40.729359 }
}
This works:
db.friends.find({
"PLAYDATE_RANGE":{
"$geoIntersects":{
"$geometry":{
"type":"Point",
"coordinates":[-73.98652, 40.752044]
}
}
}
})
This does not:
db.friends.find([
{
"PLAYDATE_RANGE":{
"$geoIntersects":{
"$geometry":{
"type":"Point",
"coordinates":[-73.98652, 40.752044]
}
}
}
},
{
"FRIEND_POSITON":{
"$geoNear":{
"near":{
"type":"Point",
"coordinates": [-73.98652, 40.752044]
},
"maxDistance":300
}
}
}
])
Please help me with the query above that does not work.
This requires an aggregate pipeline. As per mogodb doc for $geoNear, You can only use $geoNear as the first stage of a pipeline. The aggregate function has an entry for an additional query which is where the polygon query will be used to narraw down results based on inclusion in the PLAYDATE_RANGE field of the document.
db.friends.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [-73.98652, 40.752044] },
maxDistance: 300,
distanceField: "friends.calculated_distance",
query: {
"PLAYDATE_RANGE": {
"$geoIntersects": {
"$geometry": {
"type": "Point",
"coordinates":[-73.98652, 40.752044]
}
}
}
},
spherical: true
}
}
])
P.S. note that only one geospatial index can be used so put it on the FRIEND_POSITION field. If adding a 2sphere index that requires a correctly formed GeoJSON value, specifically,
"FRIEND_POSITION" : { "type" : "Point", "coordinates" : [ -73.992188, 40.729359 ] }
So the document should look like:
{
"_id" : "objid",
"FRIEND_NAME" : "Bobby",
"GEOMETRY" : {
"type": "Polygon",
"coordinates":[[
[-73.98779153823898,40.718233223261],
[-74.004946447098,40.723575517498],
[-74.006771211624,40.730592217474],
[-73.99010896682698,40.746712376146,
[-73.973135948181,40.73974615047701],
[-73.975120782852,40.736128627654],
[-73.973997695541,40.730787341083],
[-73.983317613602,40.716639396436],
[-73.98779153823898,40.718233223261]
]]},
"FRIEND_POSITION" : {
"type" : "Point",
"coordinates" : [ -73.992188, 40.729359 ]
}
}

MongoDb $near and query

I have a collection of documents in structure as below
{ _id: ObjectId("54723e44ec73a702fc979fc9"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.1258020000000215, 51.44695 ] }
}
I am running the following query to try and find documents where the start is 2000 units from a point and the end is 1 unit from a point.
"Start" :
{ "$near" :
{ "$geometry" :
{ "type" : "Point",
"coordinates" : [-0.12580200000002151, 51.44695]
}
},
"$maxDistance" : 2000.0
},
"End" :
{ "$near" :
{ "$geometry" :
{ "type" : "Point",
"coordinates" : [-0.12580200000002151, 51.44695]
}
},
"$maxDistance" : 1.0
}
When I run the query it always returns the documents as if it is doing an or. So where start is x units from a point OR end is x units from a point. So if I run it over the following two documents it returns both where I would only expect the first to be returned.
{ _id: ObjectId("54723e44ec73a702fc979fc9"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.1258020000000215, 51.44695 ] }
}
{ _id: ObjectId("54724f0cec73a70c383a27d4"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.09553900000003068, 51.427025 ] }
}
I am sure I should be able to do this as in
http://blog.mongodb.org/post/50984169045/new-geo-features-in-mongodb-2-4
"Additionally, we can have multiple 2dsphere indexes in the same compound index. This allows queries like: “Find routes with a start location within 50 miles from JFK, and an end location within 100 miles of YYC”."
For clarrification. The query shown above is supposed to be doing and AND query on START location $near point AND END location $near point. But what it actually appears to be doing is START location $near point OR END location $near point.
How do I do and AND query on two $near queries in a single document?