Hi all, hope you are well.
I have a collection with a few documents and when I run a specific geoNear query one of my objects is not retrieved as it should. This only happens with this specific document and only with this specific query (that I detected so far). I removed all other documents from the collection that I could to still replicate the error, which means that if you remove ANY of the objects from the collection the query will work as expected.
Here are the collection's documents: Collection
To replicate the error after you create the collection and add the documents to it, you need to create a 2dsphere
index:
db.collectionName.createIndex( { loc : "2dsphere" } )
And run the following command:
db.collectionName.aggregate([
{"$geoNear":{"near":{"type":"Point","coordinates":[144.960662,-37.818133]},"spherical":true,"distanceField":"dist","limit":null,"maxDistance":5000,"query":{"hobby_id":{"$in":[1,2,7]}}}},
{"$sort":{"datetime":-1}}
])
The problematic document is the following:
{
"_id" : ObjectId("57f47e690e8620049e3e4511"),
"loc" : {
"type" : "Point",
"coordinates" : [
145.001541137695,
-37.8015441894531
]
},
"datetime" : ISODate("2016-10-05T15:15:37.000+11:00"),
"msg" : "57f47e690e8620049e3e4511",
"filter_id" : 1.0
}
Note that is was supposed to be the second element when you run the query above, but it is not shown at all. Its distance to the given point is 4041.74170931192
meters so it's not being filtered out by the geoNear distance filter.
If you delete any other document from the collection it will be the second item shown and if you remove the filter_id
2
or 7
from the query it will also work and the document will show up as the second in line.
The MongoDB
version I'm using is 3.2.7
and it is running on a Ubuntu 14.04
. Currently, this is the only document with which I've been able to see this behavior but I guess it's essential to understand what is causing it and fix it before it happens in production. Does anyone have a clue on what might be going on? It looks like a MongoDB
bug to me. I'll be pleased to provide any missing information upon request.
Thank you all very much in advance!
The problematic document is the following:
{ "_id" : ObjectId("57f47e690e8620049e3e4511"), "loc" : { "type" : "Point", "coordinates" : [ 145.001541137695, -37.8015441894531 ] }, "datetime" : ISODate("2016-10-05T15:15:37.000+11:00"), "msg" : "57f47e690e8620049e3e4511", "filter_id" : 1.0 }
Note that is was supposed to be the second element when you run the query above, but it is not shown at all. Its distance to the given point is
4041.74170931192
meters so it's not being filtered out by the geoNear distance filter.
db.collectionName.aggregate([{"$geoNear":{"near":{"type":"Point","coordinates":[144.960662,-37.818133]},"spherical":true,"distanceField":"dist","limit":null,"maxDistance":4500,"query":{"filter_id":{"$in":[1,2,7]}}}},{"$sort":{"datetime":-1}}])
If you delete any other document from the collection it will be the second item shown and if you remove the
filter_id
2
or7
from the query it will also work and the document will show up as the second in line.
Hi Gustavo,
This is because if you specify filter_id
for value 1, 2 or 7 you have the aggregation result over 100 documents. As you specify limit
to null
, $geoNear operator uses the default limit of 100 documents.
Essentially, you are getting the first 100 documents that match query
and whose coordinates satisfy maxDistance
, sorting those 100 documents by datetime
. This is why if you remove filter_id
2 or 7 you are getting the result, because the total aggregation result is less than 100 documents.
You can try this, by specifying a limit to 105, for example:
db.collectionName.aggregate([
{"$geoNear":
{"near":
{"type":"Point",
"coordinates":[144.960662,-37.818133]},
"spherical":true,
"distanceField":"dist"
,
"limit":105,
"maxDistance":4500,
"query":{"filter_id":{"$in":[1,2,7]}}
}},
{"$sort":{"datetime":-1}}
]);
Regards,
Wan.
it would return all the documents that match the query and the distance. Is there a way of doing this?
Hi Gustavo,
$geoNear is an operation that outputs documents in order of nearest to farthest from a specified point. In other words, the output returned to you is already ordered by distance. Setting an unlimited result sorted may not be ideal in this case.
An alternative is to use $geoWithin instead, which outputs documents that exist entirely within a specified shape. Using your example:
db.collectionName.find({loc:
{$geoWithin:
{$centerSphere:[[144.960662,-37.818133], 5000]}
},
filter_id:{$in:[1,2,7]}
});
See also $centerSphere geo shape operator. The example query above was written for MongoDB v3.2.
For more geospatial query operators see GeoSpatial Query Operators. You may also find Find Restaurants with GeoSpatial Queries a useful resource.
Regards,
Wan.
Hi Gustavo,
If you require the distance being calculated server side, then $geoNear
would be a good operator for it. Depending on the application use case, you could set a reasonably high number for your requirement. For example, displaying 1000 nearest objects on a map could be sufficient.
Another option is to count the number of results using $geoWithin
, then use the result to limit $geoNear
. For example, if the count returns 237 items, then use the number as limit. Although depending on your application requirements and use case, running two queries may not be ideal.
Regards,
Wan.