Skip to content

Instantly share code, notes, and snippets.

@mrchrisadams
Created February 26, 2015 16:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrchrisadams/478352c9053d2461f2e4 to your computer and use it in GitHub Desktop.
Save mrchrisadams/478352c9053d2461f2e4 to your computer and use it in GitHub Desktop.
this is probably out of date

Finding a database that supports easy geo queries

We're using Mongolab, as they're provided by default:

https://addons.heroku.com/mongolab

MongoDB 2.2 gives us some form of geoindexing specifically for these purposes:

http://docs.mongodb.org/v2.2/applications/geospatial-indexes/#geospatial-indexes-proximity

Thankfully, Mongolab uses version 2.2 of Mongodb:

$ mongo ds045637.mongolab.com:45637/heroku_app13896884 -uUSERNAME -pPASSWORD

  MongoDB shell version: 2.2.3
  connecting to: ds045637.mongolab.com:45637/heroku_app13896884

  > db.runCommand( { buildInfo: 1 } )
  {
    "version" : "2.2.2",
    "gitVersion" : "d1b43b61a5308c4ad0679d34b262c5af9d664267",
    "sysInfo" : "Linux ip-10-2-29-40 2.6.21.7-2.ec2.v1.2.fc8xen #1 SMP Fri Nov 20 17:48:28 EST 2009 x86_64 BOOST_LIB_VERSION=1_49",
    "versionArray" : [
      2,
      2,
      2,
      0
    ],
    "bits" : 64,
    "debug" : false,
    "maxBsonObjectSize" : 16777216,
    "ok" : 1
  }

Working out an API for searching:

My plan is to write an ultra simple Sinatra app that has one endpoint:

/services/search/ll=-74,40.74

This more or less echoes the foursquare venue search API -

Would translate as a query in mongo along the lines of:

db.places.find( { "loc" : { $near : [ -74 , 40.74 ] , $maxDistance : 1000 } } )

If we don't care about ordering by distance, we could do something along the lines of:

db.places.find( { "loc": { "$within":
                            { "$center": [ [-74, 40.74], 10 ] }
                         }
                } )

This doesn't sort them by distance, and as a result is somewhat faster. But let's not worry about that until we have to.

Another approach, that is faster - using Haystack indixes

The steps above don't use an index. We can make it faster by using the geoSearch, that relies on a Haystack index:

db.runCommand( { geoSearch: "places",
                 search: { type: "restaurant" },
                 near: [-74, 40.74] } )

I'm guessing these are the extensions that Foursquare themselves contributed back to MongoDB.

Remembering we are on a round(ish) planet

The examples above of course don't take into account that we're living on a more or less spherical object.

Fortunately Mongodb takes this into account for us, if we pass in $nearSphere instead of just $near, like so:

db.collection.find( { loc: { $nearSphere: [0,0] } } )

Making this work with Sinatra

I'm used to Mongoid from previous work. So assuming that support the geo style shenanigans we're after, it looks like the most productive option I can think of using.

Looks like we can - Mongoid supports geoNear style queries, as long as we have the presence of mind to build 2d indexes beforehand for the collection.

In fact the queries look quite nice and readable.

This here is a query using the clever geoNear functions available in MongoDB, to return results in within 100m of the coords:

Services.geo_near([ -74, 40.74 ]).spherical.max_distance(100)

And here's what the code might looks like, according to the mongoid docs:

class Service
  include Mongoid::Document
  field :location, type: Array

  index({ location: "2d" }, { min: -200, max: 200 })
end

why we're using mongodb instead of Postgres

Yes, Postgres has the more complete GIS setup. Sadly noone in our team has the GIS background to set it up quickly, and mongodb works pretty much out of the box.

http://openlife.cc/blogs/2012/august/comparing-open-source-gis-implementations

Hurdles with mongoid

http://www.specialmoves.com/labs/mongodb-shows-the-way

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment