Let's add the gem to the Gemfile:
gem 'mongoid_spacial'
Now, for some minor changes in our code:
class Address include Mongoid::Document include Geocoder::Model::Mongoid include Mongoid::Spacial::Document field :street, type: String ... field :coordinates, type: Array spacial_index :coordinates end
As we have already created indexes in the database, we don't need to run the rake db:mongoid:create_indexes
command! Now, let's try our geolocation queries for the coordinates [10.123123, -87.1231231]
. Let's execute the following commands:
irb> Address.geo_near([10.923124, -87.8231232], max_distance: 1)
=> []
irb > Address.geo_near([10.923124, -87.8231232], max_distance: 2)
=> #<Address _id: 4f55abf8fed0eb2f6c00002e, _type: "Address", street: "101 Union Street", zip: nil, city: "Pasedena", state: "CA", country: "US", coordinates: [10.123123, -87.1231231], location_type: "Author", location_id: BSON::ObjectId('4f55abf8fed0eb2f6c00002d')>
If we search within a distance equal to 1 radian around [10.92, -81.82]
, we don't find our address. But if we search within a distance of two radians, we find our address. So, it works! mongoid_spacial
introduces a new criterion that taps the $geoNear
operation in MongoDB.
Let's take a few steps back and see what the difference is between $near
and $geoNear
in MongoDB.
The earth is round but maps are flat.
In MongoDB, when we use 2D spatial indexing and use $near
, it's like searching within a box or rectangle with the center of the box as the point we want to search with. Basically, the Pythagoras theorem is used to calculate the range of the box around the 2D point.
However, the earth is not flat but is a sphere. The longitudinal distances differ depending on the latitude. The default $near
query does not cater to this as it is treated as a true 2D area for searching. So, the surface area changes when we consider a point on a sphere. This is what $geoNear
does. It searches in a spherical manner and hence will give more accurate results when we use geospatial indexes.
Nothing would explain this better than an example:
irb> Address.geo_near([10.923124, -87.8231232], max_distance: 1) => []
irb> Address.geo_near([10.923124, -87.8231232], max_distance: 1, spherical: true)
=> [#<Address _id: 4f55abf8fed0eb2f6c00002e, _type: "Address", street: "101 Union Street", zip: nil, city: "Pasedena", state: "CA", country: "US", coordinates: [10.123123, -87.1231231], location_type: "Author", location_id: BSON::ObjectId('4f55abf8fed0eb2f6c00002d')>]
As we can see, just by adding an option spherical
, MongoDB does a spherical search and the results change.
18.118.27.99