Varun Oberoi
Varun Oberoi

Reputation: 692

What is difference between GeoJSON & Legacy coordinate pairs in terms of mongoDb?

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

Answers (1)

zero323
zero323

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

Related Questions