Build spatial app with Mongodb, Mongoid and rails 3

Location-based web application is very popular recently, so how to build a spatial app with rails. First you have to choose database to store your geo data, NoSQL is hot recently some of them is said to be scalable, high performance, one of them is MongoDB which is used by Foursquare(one of the most popular location-based service), it has built-in [geospatial index support](http://www.mongodb.org/display/DOCS/Geospatial+Indexing).

There are two popular ruby libraries for MongoDB: [Mongoid](http://mongoid.org/) and [MongoMapper](http://mongomapper.com/). We’re going to use Mongoid which is completed rails 3 compatible(use ActiveModel).And of course we’ll use rails 3.

So here we go:

**Install MongoDB in snow leopard:**

Download it from [http://www.mongodb.org/downloads](http://www.mongodb.org/downloads) , choose the package fit for your operation system. Uncompress the package put the mongodb folder under /opt/ and then add **/opt/monogodb/bin/** to **PATH**, after that you can execute mongodb command from terminal. Next step to finish setup mongodb is to create data folder in /data/db where your mongodb data stores.

Start mongodb daemon:

sudo mongod
Open mongodb console:

mongo

You will see something like (execute queries after ‘>’):

MongoDB shell version: 1.6.5
connecting to: test
>

Install rails 3:

sudo gem install rails

Create new rails 3 application:

rails new spatial_app –skip-activerecord

Edit Gemfile add follow lines:

gem “mongoid”, “2.0.0.rc.6”
gem “bson_ext”, “~> 1.2”

Run ‘bundle install’ to install mongoid.

Command to generate mongoid configuration file (it will generate config/mongoid.yml where config mongodb connection):

rails generate mongoid:config

Generate model to store spatial data:

rails g model Place

Edit your model file like this:

class Place
include Mongoid::Document
field :location, :type => Array
index [[ :location, Mongo::GEO2D ]], :min => -100, :max => 100
end

‘include Mongoid::Document’ will mapping the class to mongodb collections(http://www.mongodb.org/display/DOCS/Collections)

‘field :location, :type => Array’ will define a field with type Array named location.

‘index’ line define the spatial index . The min/max range is used to limit lat/lng value.

After that you need to run command to generate index in MongoDB:

rake db:mongoid:create_indexes

You can check the index on MongoDB console:

$ mongo
MongoDB shell version: 1.6.5
connecting to: test
> use spatial_app_development;
> db.places.getIndexes();

will see something include:

{
“ns” : “spatial_app_development.places”,
“min” : -200,
“key” : {
“location” : “2d”
},
“max” : 200,
“name” : “location_2d”
}

Add data into collections(You may import geo data from external sources):

place_1 = Place.create(:location => [ 31.64, -88.3177778 ])
place_2 = Place.create(:location => [ 33.4334523, -88.297258])

Notice: the lat/lng value have to betweetn min/max defined in the place model otherwise the record will not be saved.

Methods to query nearest places in certain distance away:

Place.near(:position => [ 31, -88, 10 ])
Place.where(:location.near => [ 22.5, -21.33 ])

Query places within bounds:

Place.where(:location.within => { “$center” => [ [ 50, -40 ], 1 ] })

So that’s most of things you need of model side to build a spatial application, to go deeper you may need to checkout [Google Map API](http://code.google.com/apis/maps/documentation/javascript/tutorial.html) and find base GEO data to get start, but that’s too much for this post :).