I currently have a query on MongoDB which queries for devices located within a certain distance of a location. It's been working perfectly fine for months now. When I upgraded from MongoDB 2.4.10 to 2.6.3, the query no longer works and it returns no results.
{
"lastLocation": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [ -122.195 , 37.423]
}
},
"$maxDistance": 10000
}
}
After playing around with it, it seems that without $maxDistance, the query works. However, I can't get $maxDistance to work at all.
I have two databases side by side with the exact same data, one with each version of MongoDB, 2.4 returns data, 2.6 does not (so it's not because there aren't devices within that distance).
Is there a known issue with maxDistance, or was there a change in units or how it works?
Index is as follows:
{
v: 1,
name: "lastLocation_2dsphere",
key: {
lastLocation: "2dsphere"
},
ns: "s-dev.devices",
background: true,
safe: true
}
Sample entry:
"lastLocation": [-122.19888, 37.42316]
Yes there have been a few changes in 2.6, kind of hidden in the documentation. In your case, in version 2.6 the $maxDistance needs to be inside of the $near document, not outside:
$maxDistance ChangesĀ¶
Description
For $near queries on GeoJSON data, if the queries specify a $maxDistance, $maxDistance must be inside of the $near document. In
previous version, $maxDistance could be either inside or outside the
$near document.
$maxDistance must be a positive value.
Solution
Update any existing $near queries on GeoJSON data that currently have the $maxDistance outside the $near document
Update any existing queries where $maxDistance is a negative value.
http://docs.mongodb.org/manual/release-notes/2.6-compatibility/
So in your case the query needs to look like this:
{
"lastLocation": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [ -122.195 , 37.423]
},
"$maxDistance": 10000
}
}
}
Related
In my application I would like to query items that are close by (e.g. within 5km) to a coordinate and I tried to use $near to achieve that. With a quick look I thought it worked but after I tested it further it seems the query is somewhat inaccurate. Here is my setup:
I selected 2 coordinates that are a bit less than 5km apart from each other:
61.4644750214197, 23.8426943813556
61.497133399999996, 23.778528100000003
(At least according to tools like this, this or this the distance between those coordinates should be about ~4,99km)
I added one of the coordinates into empty "items" collection:
db.items.insert({
"geo" : {
"type" : "Point",
"coordinates" : [
61.4644750214197,
23.8426943813556
]
}
});
I added "2dsphere" index to the collection make geospatial queries possible:
db.items.createIndex( { geo : "2dsphere" } )
Finally, I used the other coordinate with $near query:
db.items.find({geo: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 61.497133399999996, 23.778528100000003 ]
},
$maxDistance: 5000 // according to docs with '2dsphere' index and GeoJSON this is is meters
}
}}).count()
I expected the result to be 1 but instead it is 0. Even if I set $maxDistance to 7000 the result is still 0, but if I set it to 8000 the result will be 1.
Am I doing something wrong or are MongoDB geospatial queries (or just $near query?) that inaccurate? If so, is there a better way to get accurate results for this kind of query? This is my first time dealing with geospatial queries in MongoDB so there is probably a trivial explanation for my problem.
EDIT:
Basically I was dreaming of a functionality to show all items in map within X kilometres from users current location and X could be determined by user. It would be awkward if an item within 5km would not be visible even when the user wants to filter items within 7km.
I have tried most of the options for doing this query, like $centerSphere, $nearSphere and geoNear with similar results. They all seem to claim that the distance between my earlier mentioned coordinates is somewhere between 7-8km. I'm starting to think either 1. I'm missing some key peace of information about how distances work in general or 2. it simply is not possible to solve my problem with mongodb. Below are my queries for the other options:
$centerSphere (0 results with 5, 6 and 7km but 1 result with 8km):
db.items.find( { geo: {
$geoWithin: { $centerSphere: [ [ 61.497133399999996, 23.778528100000003 ], 5/6378.1 ]
}
}}).count()
geoNear (0 results with maxDistance 5000, 6000 and 7000 but 1 result with 8000):
db.runCommand(
{
geoNear: "items",
near: { type: "Point", coordinates: [ 61.497133399999996, 23.778528100000003 ] },
spherical: true,
maxDistance: 5000
}
)
I understand I am late to the party, but for all those who are facing similar issue
The problem here is that when you store that data into "coordinates", it must be in the [longitude, latitude] order because this is how mongodb works. https://docs.mongodb.com/manual/geospatial-queries/#spherical I just ran your example with reversed order of coordinates and it worked as expected.
db.items.insert({
"geo" : {
"type" : "Point",
"coordinates" : [
23.8426943813556,
61.4644750214197
]
}
});
And then i ran
db.items.find({geo: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 23.778528100000003 , 61.497133399999996]
},
$maxDistance: 5000
}
}}).count()
The count here is 1:
Hope it helps
Hello MongoDB documentation specifies that there are several ways to retrieve documents near a geographical position :
using "queries" (in find queries for instance) :
https://docs.mongodb.com/v3.0/reference/operator/query-geospatial/
or using "commands" :
https://docs.mongodb.com/manual/reference/command/nav-geospatial/
I don't understand the difference between commands and operator/queries ? These commands seem to do exactly the same thing as their query counterparts ?
PS : I use scala reactivemongo connector in my application.
I remembered reading it from mongodb definitive guide 2nd edition (mongo 2.6), however this book only covers mongo2.6.
query command cover several tasks like CRUD, drop database. While database Command cover everything else, including administrative tasks, cloning database, etc. (this book uses mongodb v2.6, I am sure in mongodbV3.2 queryCommand has more functions that can cover some adminitrative tasks)
query in mongoshell returned a cursor, while database command returned an document that always has "ok" status, and one or more information.
example querying geolocation with database Command
db.runCommand( {
geoNear: <collection> ,
near: { type: "Point" , coordinates: [ <coordinates> ] } ,
spherical: true,
...
} )
example of querying database with query command
db.places.find(
{
location:
{ $near :
{
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$minDistance: 1000,
$maxDistance: 5000
}
}
}
)
If I have documents like this:
{firstname:"Jordan", lastname:"Snyder", age:6, homelocation:[<longitude, latitude>]}
In the mongo shell, how do I all the "distinct" firstname's across matching documents of people who live near a specific point (say 1 mile)? I see mongo has a distinct db.collection.distinct(field, query), but all the samples I see for finding anything "near" or "geowithin" (using homelocation field in my case) is using db.collection.find. I don't want all documents, I just want the distinct list of firstnames.
The query parameter of distinct uses the same format as the query selector parameter of find. So assuming a 2dsphere index on homelocation you can do something like:
db.test.distinct('firstname', {
homelocation: {
$near: {
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$maxDistance: 1600 // In meters
}
}
})
I am using a single MongoDB 3.0.1 instance (without sharded cluster, replicas, etc) with one database containing a collection with 15324247 points. Of course, points are indexed with a 2dsphere index. Queries are done through a Node.js app.
Looking for points near a concrete lon&lat, it requires 11710ms to return 59925 points.
The same query including a restricted project (only geometry), it still requires 4351ms to return 59925 points.
find({
"geometry": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [110.30838012695312,
-20.86522808076763]
},
"$maxDistance": 1000
}
}
},
{
geometry: 1
})
Changing the query and using and aggregation instead of find it requires: 5799ms but returns 8882 points, and projecting only the geometry 4606ms returns 8882 points.
aggregate([{
"$geoNear": {
"near": {
"type": "Point",
"coordinates": [110.30838012695312,
-20.86522808076763]
},
"distanceField": "dist.calculated",
"maxDistance": 964,
"spherical": true,
"num": 70000
}
}])
Although all the elements are indexed, is this a normal performance? How could be improved? I have tried $geoWithin instead of $geoNear, or adding more keys to geoindex, using cursor.get instead of cursor.on in Node.js side, increasing/decreasing batchSize for aggregation... but performances are quite similar in all cases.
And the second question is why the aggregation is returning less results than the find?
I'm having a series of points which forms a poly-line (path). I need to store it in the mongodb and query it nearby point.
How to store a poly-line in the mongodb?
Can i query it with a $near?
After saving the poly-line to mongodb, i will have a point and distance from the point and need to query the db.
EDIT :
i'm gone track the user's location using the GPS and i need to save the path in mongodb, how to do this?
Then the user can able to search path nearby his place with certain distance so i need to search the mongodb with the $near function.
So what you want is actually a LineString GeoJSON type, which is supported by MongoDB:
{
"loc": {
"type": "LineString",
"coordinates": [ [ 40, 5 ], [ 41, 6 ] ]
}
}
This allows you record a set of "coordinates" along a "path" that you wish to contain as a singular object in your data store. The main beauty of this is that you can do geospatial queries against such an object ( rather than a distinct "Point" and retrieve the whole "set" of connecting "Points" in a single document as "nearest". Better yet "multiple shapes" like this can be matched with ease.
So then you can just query with $near or other operators as appropriate:
db.collection.find({
"loc": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [ 41,5 ]
},
"$maxDistance": 10000
}
}
})
A $near operator in a query will return the results ordered by the "nearest" to the queried GeoJSON object or legacy coordinate point provided to the query.
That should basically work for you.