Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB with Mongoid in Rails - Geospatial Indexing

MongoDB has a very nice Geospatial Indexing feature. How can I use it in Rails with Mongoid?

like image 731
CamelCamelCamel Avatar asked Oct 09 '11 08:10

CamelCamelCamel


People also ask

How does MongoDB Geospatial index work?

MongoDB supports spherical surface calculations on legacy coordinate pairs via a 2dsphere index by converting the data to the GeoJSON Point type. To specify data as legacy coordinate pairs, you can use either an array (preferred) or an embedded document.

Does MongoDB automatically create indexes?

Single fieldEach collection in MongoDB automatically has an index on the _id field. This index can then be used to fetch documents from the database efficiently. However, you will need to query data on other specific fields most of the time.

Can MongoDB use multiple indexes?

MongoDB can use the intersection of multiple indexes to fulfill queries. In general, each index intersection involves two indexes; however, MongoDB can employ multiple/nested index intersections to resolve a query.

What is clustered index in MongoDB?

A clustering index is an index that stores the entire document, not just the defined key. A common example is InnoDB's primary key in MySQL. InnoDB stores the entire row in the primary key, therefore making it clustering. MongoDB has no clustering indexes, as the entire document is stored in a data heap.


2 Answers

You can define geo indexes like this in mongoid

class Item
  include Mongoid::Document

  field :loc, :type => Array

  index(
      [
          [:loc, Mongo::GEO2D]             
      ], background: true

  )
end

And for queries

$near command (without maxDistance)

 location = [80.24958300000003, 13.060422]
 items = Item.where(:loc => {"$near" => location})

$near command (with maxDistance)

 distance = 10 #km
 location = [80.24958300000003, 13.060422]
 items = Item.where(:loc => {"$near" => location , '$maxDistance' => distance.fdiv(111.12)})

Convert distance by 111.12 (one degree is approximately 111.12 kilometers) when using km, or leave distance as it is on using degree

$centerSphere / $nearSphere queries

location = [80.24958300000003, 13.060422]
items = Item.where(:loc => {"$within" => {"$centerSphere" => [location, (distance.fdiv(6371) )]}})

This will find the items within the 10 km radius. Here we need to convert the distance/6371(earth radius) to get it work with km.

$box (bounding box queries)

 first_loc = [80.24958300000003, 13.060422]
 second_loc = [81.24958300000003, 12.060422]
 items = Item.where(:loc => {"$within" => {"$box" => [first_loc, second_loc]}})

This will help you to find the items within the given bounding box.

like image 141
RameshVel Avatar answered Nov 03 '22 07:11

RameshVel


RameshVel's answer is great.

As an update, in Mongoid 3.0.4, I had to define the index as follows to make it work with rake db:mongoid:create_indexes:

index(
  { loc: Mongo::GEO2D },
  { background: true }
)
like image 37
Jake Vose Avatar answered Nov 03 '22 07:11

Jake Vose