Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Geo-spatial queries in MongoDB

Geo-spatial queries in MongoDB

My lightening talk from the Melbourne MongoDB meetup, on how there are multiple ways to query geo-spatial indexes

Dougal MacPherson

March 06, 2012
Tweet

More Decks by Dougal MacPherson

Other Decks in Programming

Transcript

  1. First you need a geo-spacial index on your collection. db.places.ensureIndex({

    location : "2d" }) Your values will need to be "within earth like bounds" ★ latitude -180 to 180 ★ longitude -90 to 90 You can specify other ranges incase you're not dealing with 'earth like bounds' db.places.ensureIndex( { location : "2d" } , { min : -500 , max : 500 } ) page 2
  2. ings to be aware of e order in the array

    that you are indexing matters. longitude/latitude - otherwise you’re results are going to be wildly inaccurate. db.places.insert({ location : [30, 40] }) page 3
  3. Find $near Query for things that are nearby to a

    longitude/latitude db.places.find({"location" : {"$near" : [32, 42]}}) Documents are returned in the order of distance from the location By default will return 100 documents, unless you specify a limit db.places.find({"location" : {"$near" : [32, 42]}}).limit(35) page 4
  4. Find $within You can query for points within a shape

    ★ a circle ★ a square ★ polygon Your result-set is not sorted by distance, as a result this type of query is a bit quicker page 5
  5. Find within circles You need to pass in the radius

    of the circle to de ne the size of it. db.places.find({"location" : { "$within" : {"$center" : [center, radius]}}}) page 6
  6. Find within Polygons As of MongoDB v2+ you can query

    on polygons. myArea = [[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]] db.places.find({ "location" : { "$within" : { "$polygon" : myArea } } }) If you’re not using MongoDB version 2, you probably should page 7
  7. geoNear Returns the distance of each document from the location,

    as part of the resultset. Handy if you needed to show the distance from document to your location db.runCommand({ geoNear: 'locations', near: [32,42], maxDistance: 10 }) e maxDistance argument limits the distance from the central point. is example below quotes '10' degrees, realistically your numbers will be much smaller page 8
  8. Your result-set will look something like this… { "ns" :

    "db.places", "near" : "1100010101001101111001111100010101", "results" : [ { "dis" : 1.924482540031314, "obj" : { "_id" : ObjectId("4f470841fb8d5f0b9a000023"), "location" : [ 33.81820081650795, 42.630697104587625 ], "name" : "My place" } }] continued… page 9
  9. "stats" : { "time" : 0, "btreelocs" : 0, "nscanned"

    : 12, "objectsLoaded" : 1, "avgDistance" : 1.924482540031314, "maxDistance" : 1.924493274866918 }, "ok" : 1 Note the handy stats page 10
  10. e distance is quoted in radians Which typically isn’t very

    useful. To the best of my knowledge you will need to calculate the distance in meters yourself. Question is how accurate you need your measurements to be. page 11
  11. e earth isn't at, but MongoDB treats it as such

    (generally) Need to note that MongoDB treats your location queries as earth is a at two dimensional plane. It's a case of tradeoffs with accuracy and speed, as not only is the earth not at, it's also not perfectly spherical. If your calculations are near the poles, cover a lot of a area or need to be really accurate, you’ll need to do some math… http://en.wikipedia.org/wiki/Haversine_formula ere is no wrapping at the poles and international date line, although mongo will raise an error page 12
  12. Geospatial Haystack Indexes Assuming you have a lot of data,

    you can split your geospatial indexes into smaller buckets. So that queries only utilise the indexes that are closest to them. eg: your search only uses the index for eastern Australia and not the whole world is is only appropriate if the documents are reasonably close together db.places.ensureIndex({ location : "geoHaystack", type : 1 }, { bucketSize : 10 }) “bucketSize” = degrees latitude/longitude page 13
  13. A haystack index can only be used by a database

    command, a.k.a geoNear db.runCommand({ geoSearch : "places", near : [32, 42], maxDistance : 6, search : { type : "bar" }, limit : 30 }) page 14
  14. Links e documentation is actually really good http://www.mongodb.org/display/DOCS/Geospatial+Indexing Presentations on

    geo-spatial http://www.slideshare.net/ggoodale/geospatial-indexing-and-querying-with-mongodb page 15