Here’s a little gist that I wrote to illustrate the difference between MongoDB‘s use of degrees vs. radians in its non-spherical and spherical geospatial queries:
> db.dropDatabase(); | |
{ "dropped" : "test", "ok" : 1 } | |
> | |
> // These points are one degree apart, which (according to Google Maps) is about 110 km apart | |
> // at this point on the Earth. | |
> db.points.insert({location: [-122, 37]}); | |
> db.points.insert({location: [-122, 38]}); | |
> db.points.ensureIndex({location:"2d"}); | |
> | |
> | |
> // Non-spherical geospatial queries use degrees: | |
> | |
> // $near finds both points because they are within 1 degree of this point between them | |
> db.points.find({location: {$near:[-122, 37.5], $maxDistance: 1}}); | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
{ "_id" : ObjectId("4dc8fa2f01b6eeba7bb69857"), "location" : [ -122, 38 ] } | |
> // Same is true for $within $center | |
> db.points.find({location: {$within: {$center:[[-122, 37.5], 1]}}}); | |
{ "_id" : ObjectId("4dc8fa2f01b6eeba7bb69857"), "location" : [ -122, 38 ] } | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
> | |
> // $near finds only one point because only the first point is within 1 degree of this point | |
> // If $near used radians, a distance of 1 radian would be 6,378 km, and this would return both points. | |
> db.points.find({location: {$near:[-122, 36.5], $maxDistance: 1}}); | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
> // Same behavior for $within $center | |
> db.points.find({location: {$within: {$center:[[-122, 36.5], 1]}}}); | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
> | |
> | |
> // Spherical geospatial queries use radians: | |
> var earthRadius = 6378; // in km | |
> | |
> // Finds both points because they are within 60 km of this point between them | |
> // If $nearSphere used degrees, this distance would be 0.009 degrees and wouldn't return any points | |
> db.points.find({location: {$nearSphere:[-122, 37.5], $maxDistance: 60/earthRadius}}); | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
{ "_id" : ObjectId("4dc8fa2f01b6eeba7bb69857"), "location" : [ -122, 38 ] } | |
> // Same behavior for $within $centerSphere | |
> db.points.find({location: {$within: {$centerSphere:[[-122, 37.5], 60/earthRadius]}}}); | |
{ "_id" : ObjectId("4dc8fa2f01b6eeba7bb69857"), "location" : [ -122, 38 ] } | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
> | |
> // Finds only one point because only the first point is within 60km of this point to the north | |
> db.points.find({location: {$nearSphere:[-122, 36.5], $maxDistance: 60/earthRadius}}); | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } | |
> // Same behavior for $within $centerSphere | |
> db.points.find({location: {$within: {$centerSphere:[[-122, 36.5], 60/earthRadius]}}}); | |
{ "_id" : ObjectId("4dc8fa2c01b6eeba7bb69856"), "location" : [ -122, 37 ] } |