Skip to content
Geo-spatial extension for Mongoid 2
Ruby JavaScript
Find file
New pull request
Fetching latest commit...
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
lib using ideas from mongoid spacial
spec rename some files, make they donot break mongoid's methods like first…
.document added document file


Mongoid geo

Status update: August, 2011

This project is currently dead, as I can find no time to keep it alive for the time being. The project mostly works, except for
`monogid/contexts/geo_mongo.rb`, which needs some loove ;)

The project mongoid_spacial by @ryanong has taken many of the ideas and core design of mongoid_geo, improved, reworked and optimized it and added many new features such as pagination intgration etc.

Please use the mongoid_spacial gem instead!!

Note: I have created several other “geo” projects in various states, some currently with a “refactor” branch.
Would be nice to finish those and have it all integrated some time :)


Running specs

The goal of this branch is to define a good specs structure and build up a good design of this ‘geo’ add-on this way.

$ bundle
$ bundle exec rspec spec/mongoid/geo/config_spec.rb

Status update: June, 2011

- A Mongoid::Geo::Config object has been added which you use to configure Mongoid::Geo, see mongoid/geo/config_spec.rb
- GeoPoints and GeoVectors can be integrated using the new #enable_extensions! method on Mongoid::Geo::Config, specs in mongoid/geo/extensions demonstrate how to use this
- Creation of Mongo query hashes for Twin- and NestedOperators have been extracted into Query classes (see mongoid/geo/queries folder)
- #geo_near now uses configuration from Mongoid::Geo::Config, such as the #distance_calculator (if Mongo server doesn’t support this) and the #radians_multiplier etc.
- extensions can be enabled using Mongoid::Geo.enabele_extension ; currently supported extensions are :geo_calc, geo_point and geo_vectors (see specs for usage examples)

Example Usage 1.0 (goal)

class Address
  field :location, :type => Array, :geo => true

my_home = :location => {:lat => 10, :lng => 12}.to_lng_lat
my_job = :location => [10.2, "12.1"].to_lng_lat
my_club = :location => [10.2, 12.1]
my_club.location_lat == 12.1 # true
my_club.location_lng == 10.2 # true

nearest_locations = Address.geo_near my_club

# find near point, max distance
Address.where :location.near_max => [{:latitude => 10, :longitude => 12 }, 5] # 5 km?
Address.where :location.near_max => [my_club, 5]

Address.where(:location.within_box => [my_job, my_club])
Address.where(:location.within_center(:sphere) => [my_home, 5])

# geo_point integration (using GeoPoint class)

Mongoid::Geo::Config.enable_extension! :geo_point

p1 = "58 38 38N, 003 04 12W".geo_point # DMS format support!
my_home = :location => p1.to_lng_lat

# a GeoPoint includes some nice geo calculation methods, that are calculated relative to itself !
p1.bearing_to my_club.geo_point # => 60 deg ?
p1.distance_to my_home.geo_point # => 2341 kms ?

# geo_vectors integration

Mongoid::Geo::Config.enable_extension! :geo_vectors

my_home = :location => p1.to_lng_lat
my_home.add [2, 4].vector # add lng/lat vector
my_home.add [20,].vector # add vector of 4km at 20 degrees

Example Usage 1.1 (goal)

Would be nice with a simple API that acts as a location repository and can be implemented for any key/value store.
Would also be nice to use unit distances as Numeric macros (currently available in geo_magic gem).

Address.where(:location.within_box => [:my_job, :my_club]) # each point should be looked up in the repo using the symbol as key  
Address.where :location.near_max => [:my_home, 5000.meters] # use geo_magic distance here!


This is a Geo extension for Mongoid 2.

MongoDB Geospatial Indexing

  • Supports Mongo DB 1.7+ sphere distance calculations
  • Extra geo calculation methods such as #near_sphere etc.
  • Adds concept of a special “geo” field (for setting the location point)
  • Configure and create geo indexes
  • Calculate locations near a given point and return as criteria, sorted by distance

You need help?

Post questions in the mongoid-geo group. Here I (and other uses of mongoid-geo) will
try to help out and answer any questions.

Suggestions, improvements and bugs?

Please raise issues or suggestions for improvements in the “Issues” section on github.
I would recommend that you try to branch the project, try to fix it yourself and make a pull request.

Current integrations

Mongoid geo has now been integrated with Google-Maps-for-Rails, thanks to oli-g, see commit

Mongoid 2 geo features

The following summarized what geo functionality is already provided by Mongoid 2.0 (as far as I could tell, May 9th, 2011)

Find addresses near a point

  Address.near(:latlng => [37.761523, -122.423575, 1])

Find locations within a circle

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

Create geo-spatial index

  class Person
    field :location, :type => Array
    index [[ :location, Mongo::GEO2D ]], :min => -180, :max => 180

  # to ensure indexes are created, either:
  Mongoid.autocreate_indexes = true

  # or in the mongoid.yml
  autocreate_indexes: true

These are the only geo features I could find that are currently built-in for Mongoid 2.

Mongoid Geo implements some nice extra geo features:

Mongoid Geo features

The following briefly demonstrates all the features that mongoid-geo provides:

Geo index

A new geo_index class method

Usage example:

geo_index :location

Note: For embedded documents, you must define the index in the root collection class. (davemitchell)

Calling geo_index also adds a #create_index! method to the class to enable construction of the index (on the instances/data in the DB).

  class Address
    geo_index :location

I also added a nice little Array macro so you can do this:

  [Address, Location].create_geo_indexes!

Geo option for Array GPS location field

Objective: When setting a geo GPS location array, the setter should try to convert the value to an array of floats

The “old” manual way:

  class Person
    field :locations, :type => Array

    def locations= args
      @locations = args.kind_of?(String) ? args.split(",").map(&:to_f) : args

mongoid-geo provides a new :geo option that can be used with any Array field:

Usage example:

  class Person
    field :location, :type => Array, :geo => true

    geo_index :location

   p =

   # A Geo array can now be set via String or Strings, Hash or Object, here a few examples...
   # Please see geo_fields_spec.rb for more options!

   p.location = "45.1, -3.4"
   p.location = "45.1", "-3.4"
   p.location = {:lat => 45.1, :lng => -3.4}
   p.location = [{:lat => 45.1, :lng => -3.4}]
   p.location = {:latitude => 45.1, :longitude => -3.4}  

   my_location  = :latitude => 45.1, :longitude => -3.4
   p.location   = my_location

   # for each of the above, the following holds
   assert([45.1, -3.4], p.location)

   # also by default adds #lat and #lng convenience methods (thanks to TeuF)
   assert(45.1 ,
   assert(-3.4 , p.lng)

Customizing lat/lng attribute names:

    # the #lat and #lng convenience methods can also be customized with the :lat and :lng options
   field :location, :type => Array, :geo => true, :lat => :latitude, :lng => :longitude

   assert(45.1 , p.latitude)
   assert(-3.4 , p.longitude)

   # or set the array attributes using symmetric setter convenience methods!
   p.latitude   = 44
   assert(44 , p.latitude)

Reversing lat/lng for spherical calculations

  # You can also reverse the lat/lng positioning of the array storage - this is fx useful for spherical calculations
  Mongoid::Geo.spherical_mode do
    # Mongoid::Geo.lat_index.should == 1
    # Mongoid::Geo.lng_index.should == 0
    address.location = "23.5, -47"
    address.location.should == [23.5, -47].reverse

  # or alternatively 
  Mongoid::Geo.spherical = true
  address.location = "23.5, -47"
  address.location.should == [23.5, -47].reverse  


class Address
  include Mongoid::Document
  extend Mongoid::Geo::Near

  field :location, :type => Array, :geo => true

# Find all addresses sorted nearest to a specific address loation
nearest_addresses = Address.geo_near(another_address, :location)

class Position
  include Mongoid::Document

  field :pos, :type => Array, :geo => true

Find all positions sorted nearest to the address loation

nearest_positions = Position.geo_near(another_address.location, :pos)

Perform distance locations in Speherical mode inside Mongo DB (default is :plane)

nearest_positions = Position.geo_near(another_address.location, :pos, :mode => :sphere)

Other options supported are: :num, :maxDistance, :distanceMultiplier, :query

GeoNear returns each distance calculated in degrees. Use the :distanceMultiplier or :unit option to return in the unit of your choice (see unit.rb).

Set :distanceMultiplier = 6371 to get distance in KMs
Set @:distanceMultiplier = @3963.19 to get distance in Miles

You can also use the :unit option instead like this (supports :feet, :meters, :kms, :miles):

results = Address.geo_near @center.location, :location, :unit => :feet, :dist_order => :desc

The geo_near query result is returned as a Mongoid::Criteria


Note that the :fromLocation field, stores the location the distance was last calculated as a Hash of the GPS location point it was calculated from:

[23.5, -47].hash

This hash can be retrieved (and used for comparison?) using the fromHash field

from = results.first.fromHash

You can also at any time get the GPS location point which the distance of any result instance was calculated from, using the @fromPoint field

from = results.first.fromPoint

You can now explicitly set/configure the Mongo DB version used. This will affect whether built-in Mongo DB distance calculation will be used or using standalone Ruby Haversine algorithm. By default the Mongo DB version is set to 1.8 (as of May 9, 2011) . See geo_near specs for more details/info on this.

Mongoid::Geo.mongo_db_version = 1.7

Mongoid Geo extra inclusions

Find addresses near a point using spherical distance calculation

  Address.near_sphere(:location => [ 72, -44 ])

Mongoid Geo extra inflections


  base.where(:location.near_sphere => [ 72, -44 ])
  # => :location => { "$nearSphere" : [ 72, -44 ] }


Find points near a given point within a maximum distance

  base.where(:location.near_max => [[ 72, -44 ], 5])
  # => { $near: [50, 40] , $maxDistance: 3 }

  base.where(:location.near_max(:sphere) => [[ 72, -44 ], 5])
  # => { $nearSphere: [50, 40] , $maxDistanceSphere: 3 }

  base.where(:location.near_max(:sphere, :flat) => [[ 72, -44 ], 5])
  # => { $nearSphere: [50, 40] , $maxDistance: 3 }

You can also use a Hash to define the near_max

  places.where(:location.near_max => {:point => [ 72, -44 ], :distance => 5})

Or use an Object (which must have the methods #point and #distance that return the point and max distance from that point)

  near_max_ = ( :point, :distance).new
  near_max.point = [50, 40]
  near_max.distance = [30,55]

  places.where(:location.near_max => near_max)

Note: For the points, you can also use a hash or an object with the methods/keys, either :lat, :lng or :latitude, :longitude


  center = ( :lat, :lng).new = 72
  center.lng = -44
  places.where(:location.within_center => [center, radius])

  # OR

  places.where(:location.within_center => [{:lat => 72, :lng => -44}, radius])


  box = [[50, 40], [30,55]]
  base.where(:location.within_box => box)
  # => locations: {"$within" : {"$box" : [[50, 40], [30,55]]}

  base.where(:location.within_box(:sphere) => box)
  # => locations: {"$within" : {"$boxSphere" : [[50, 40], [30,55]]}

You can also use a Hash to define the box

  places.where(:location.within_box => {:lower_left => [50, 40], :upper_right => [30,55]})

  # or mix and match

  places.where(:location.within_box => {:lower_left => {:lat => 50, :lng => 40}, :upper_right => [30,55] } )

Or use an object (which must have the methods #lower_left and #upper_right that return the points of the bounding box)

  box = ( :lower_left, :upper_right).new
  box.lower_left =  [50, 40]
  box.upper_right = [30, 55]

  places.where(:location.within_box => box)


  center = [50, 40]
  radius = 4

  places.where(:location.within_center => [center, radius])
  # => places: {"$within" : {"$center" : [[50, 40], 4]}

  places.where(:location.within_center(:sphere) => [center, radius])
  # => places: {"$within" : {"$centerSphere" : [[50, 40], 4]}

You can also use a hash to define the circle, with :center and :radius keys

  places.where(:location.within_center => {:center => [50, 40], :radius => 4})

Or use an object (which must have the methods #center and #radius that return the center and radius of the circle))

  circle = ( :center, :radius).new = [50, 40]
  circle.radius = 4

  places.where(:location.within_center => circle)

Note on the specs

The specs still use the old “Javascript” like method convention, such as #nearSphere
Don’t let that fool you ;)


Please feel free to contribute to the project!

I aim to deliver a complete geo package for use with Mongoid_. This gem should work nicely with geo_calc and geo_vectorsvectors that I’m also working on.

Your assistance on any of these projects will be greatly appreciated :)

Something went wrong with that request. Please try again.