Reputation: 692
I am trying to use $geoNear aggregation operator of mongoDb to calculate distances of users from current location in following way :
'$geoNear': {
near: currentLocation,
distanceField: 'distance',
spherical: true,
}
With currentLocation being something like:
{ "type" : "Point", "coordinates" : [ -122.1575745, 37.4457966 ] }
My collection is of following type (using mongoose):
users = [{
....
location : { // GeoJSON Point or I think it is ;)
type: {
type: String
},
coordinates: []
}
....
}]
I am using index (again mongoose's syntax):
userSchema.index({
location: '2dsphere'
});
Now the PROBLEM I am facing is that, if I query using currentLocation as mentioned above (in form of GeoJSON) I get weird distances (very huge numbers), but if I use currentLocation.coordinates, i.e using legacy coordinate pairs ([-122.1575745, 37.4457966]), I get correct result. But mongoDb docs for geoNear clearly says that we can query using both GeoJSON point or legacy coordinate pairs.
I am curious to know what exactly is difference between GeoJSON point and legacy coordinate pairs ?
E.g Collection:
{ "_id" : ObjectId("5277679914c6d8f00b000003"), "location" : { "type" : "Point", "coordinates" : [ 106.6202887, -6.1293536 ] } }
{ "_id" : ObjectId("5277810148219d011c000003"), "location" : { "type" : "Point", "coordinates" : [ 106.6202887, -6.1293536 ] } }
{ "_id" : ObjectId("5281c7ba2dfd7bdc64000003"), "location" : { "type" : "Point", "coordinates" : [ -86.9248483, 33.4480108 ] } }
{ "_id" : ObjectId("5281c8b82dfd7bdc64000004"), "location" : { "type" : "Point", "coordinates" : [ -74.0087126, 40.7136487 ] } }
{ "_id" : ObjectId("5281c9782dfd7bdc64000005"), "location" : { "type" : "Point", "coordinates" : [ -122.1575745, 37.4457966 ] } }
Incorrect result:
[{"location":{"type":"Point","coordinates":[-122.1575745,37.4457966]},"dis":13.69288259318155},
{"location":{"type":"Point","coordinates":[-86.9248483,33.4480108]},"dis":12697164592.388557},
{"location":{"type":"Point","coordinates":[-74.0087126,40.7136487]},"dis":16328789117.58145},
{"location":{"type":"Point","coordinates":[106.6202887,-6.1293536]},"dis":55446284682.14049},
{"location":{"type":"Point","coordinates":[106.6202887,-6.1293536]},"dis":55446284682.14049}]
Upvotes: 6
Views: 4019
Reputation: 330093
Lets create some example documents and geospatial index:
> db.foo.insert({name: "Warsaw", location: {"type" : "Point", "coordinates" : [21.016667, 52.233333]}})
> db.foo.insert({name: "Stockholm", location: {"type" : "Point", "coordinates" : [18.068611, 59.329444]}})
> db.foo.ensureIndex({"location": "2dsphere"})
Distance between Warsaw PL and and Stockholm SE is somewhere about 810 km so let's check if it works as expected. First we can fetch document for Stockholm.
> Stockholm = db.foo.findOne({name: "Stockholm"})
Now we can run query using geoNear:
> db.runCommand({ geoNear: 'foo', near: Stockholm.location.coordinates, spherical: true })
{
"ns" : "test.foo",
"results" : [
{
"dis" : 6.558558954334308e-10,
"obj" : {
"_id" : ObjectId("52876ab0b12c6fc62f5d9311"),
"name" : "Stockholm",
"location" : {
"type" : "Point",
"coordinates" : [
18.068611,
59.329444
]
}
}
},
{
"dis" : 0.12715355275490586,
"obj" : {
"_id" : ObjectId("5287697eb12c6fc62f5d9310"),
"name" : "Warsaw",
"location" : {
"type" : "Point",
"coordinates" : [
21.016667,
52.233333
]
}
}
}
],
"stats" : {
"time" : 9,
"nscanned" : 3,
"avgDistance" : 0.06357677670538088,
"maxDistance" : 0.12715355275490586
},
"ok" : 1
}
Distance between Stockholm ans Stockholm is close to 0
as expected. Distance between Stockholm and Warsaw is 0.12715355275490586
. When you run query using legacy coordinate pairs you get result in radians so we have to multiply this value by Earth radius:
> 0.12715355275490586 * 6371.0
810.0952846015052
So far so good. Lets check if we get similar result using geojson as a query.
> db.runCommand({ geoNear: 'foo', near: Stockholm.location, spherical: true })
{
"ns" : "test.foo",
"results" : [
{
"dis" : 0.004183114486663965,
"obj" : {
"_id" : ObjectId("52876ab0b12c6fc62f5d9311"),
"name" : "Stockholm",
"location" : {
"type" : "Point",
"coordinates" : [
18.068611,
59.329444
]
}
}
},
{
"dis" : 810998.0748260651,
"obj" : {
"_id" : ObjectId("5287697eb12c6fc62f5d9310"),
"name" : "Warsaw",
"location" : {
"type" : "Point",
"coordinates" : [
21.016667,
52.233333
]
}
}
}
],
"stats" : {
"time" : 4,
"nscanned" : 3,
"avgDistance" : 405499.0395045898,
"maxDistance" : 810998.0748260651
},
"ok" : 1
}
Distance between Stockholm ans Stockholm is once again close to 0
. Distance between Stockholm and Warsaw is 810998.0748260651. When you run geoNear query using GeoJSON distances are calculated in meters. 810998.0748260651 is roughly equal to 810 km so nothing strange here.
> 810998.0748260651 / 1000
810.9980748260651
Difference between both solutions could be smaller but it is just a FP arithmetics.
> Math.abs(810.0952846015052 - 810.9980748260651)
0.902790224559908
When you use find
command with $near
operator. When you create simple 2d
index on legacy coordinates pairs it can be queried using both {$near: Stockholm.location.coordinates}
and {$near: {$geometry: Stockholm.location}
. If you have 2dsperhical
only {$near: {$geometry: Stockholm.location}
will work.
Upvotes: 5