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
}
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.
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.
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] } } )
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
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