A Geo extension for Mongoid.
- Supports Mongoid 1.7 sphere distance calculations and
- Adds nearSphere inclusion method
- Adds a set of geo related inflections
- Adds an exta option for defining a “geo” field, to have the generated attr_writer parse and convert strings etc. to float arrays.
Address.near(:latlng => [37.761523, -122.423575, 1])
base.where(:location.within => { "$center" => [ [ 50, -40 ], 1 ] })
class Person field :locations, :type => Array index [[ :locations, Mongo::GEO2D ]], :min => -180, :max => 180 end # 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 are currently built-in for Mongoid 2.
Mongoid Geo implements the following extra features…
The following briefly demonstrates all the features that Mongoid Geo currently provides
Old/Manual way: index [[ :locations, Mongo::GEO2D ]], :min => -180, :max => 180
Using new geo_index class method : geo_index :locations
When setting a geo-location array, the setter should try to convert the value to an array of floats
Old/Manual way:
class Person field :locations, :type => Array def locations= args @locations = args.kind_of?(String) ? args.split(",").map(&:to_f) : args end end
With the new :geo
option supplied by mongoid-geo :
class Person field :locations, :type => Array, :geo => true geo_index :locations end p = Person.new # set via String or Strings p.locations = "45.1, -3.4" p.locations = "45.1", "-3.4" assert([45.1, -3.4], p.locations)
Find addresses near a point using spherical distance calculation
Address.nearSphere(:locations => [ 72, -44 ])
base.where(:locations.nearSphere => [ 72, -44 ]) # => :locations => { "$nearSphere" : [ 72, -44 ] }
Find points near a given point within a maximum distance
base.where(:locations.nearMax => [[ 72, -44 ], 5]) # => { $near: [50, 40] , $maxDistance: 3 } base.where(:locations.nearMax(:sphere) => [[ 72, -44 ], 5]) # => { $nearSphere: [50, 40] , $maxDistanceSphere: 3 } base.where(:locations.nearMax(:sphere, :flat) => [[ 72, -44 ], 5]) # => { $nearSphere: [50, 40] , $maxDistance: 3 }
You can also use a Hash to define the nearMax
places.where(:location.nearMax => {: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_ = (Struct.new :point, :distance).new near_max.point = [50, 40] near_max.distance = [30,55] places.where(:location.nearMax => 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
Example:
center = (Struct.new :lat, :lng).new center.lat = 72 center.lng = -44 places.where(:location.withinCenter => [center, radius]) # OR places.where(:location.withinCenter => [{:lat => 72, :lng => -44}, radius])
box = [[50, 40], [30,55]] base.where(:locations.withinBox => box) # => locations: {"$within" : {"$box" : [[50, 40], [30,55]]} base.where(:locations.withinBox(:sphere) => box) # => locations: {"$within" : {"$boxSphere" : [[50, 40], [30,55]]}
You can also use a Hash to define the box
places.where(:location.withinBox => {:lower_left => [50, 40], :upper_right => [30,55]}) # or mix and match places.where(:location.withinBox => {: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 = (Struct.new :lower_left, :upper_right).new box.lower_left = [50, 40] box.upper_right = [30, 55] places.where(:location.withinBox => box)
center = [50, 40] radius = 4 places.where(:location.withinCenter => [center, radius]) # => places: {"$within" : {"$center" : [[50, 40], 4]} places.where(:location.withinCenter(:sphere) => [center, radius]) # => places: {"$within" : {"$centerSphere" : [[50, 40], 4]}
You can also use a Hash to define the circle
places.where(:location.withinCenter => {:center => [50, 40], :radius => 4})
Or use an Object (which must have the methods #lower_left and #upper_right that return the points of the bounding box)
circle = (Struct.new :center, :radius).new circle.center = [50, 40] circle.radius = 4 places.where(:location.withinCenter => circle)