Module: Mongoid::Geospatial::ClassMethods

Defined in:
lib/mongoid/geospatial.rb

Overview

Methods applied to Document’s class

Instance Method Summary collapse

Instance Method Details

#nearby(coordinates, _options = {}) ⇒ Mongoid::Criteria

Provides a convenient way to find documents near a given set of coordinates. It automatically uses the first spatial field defined in the model and determines whether to use a planar (.near) or spherical (.near_sphere) query based on the field’s definition options (‘spatial: true` vs `sphere: true`).

Example:

Bar.nearby([10, 20])
Alarm.nearby(my_point_object)

Parameters:

  • coordinates (Array, Mongoid::Geospatial::Point)

    The coordinates (e.g., [lon, lat]) or a Point object to find documents near to.

  • _options (Hash) (defaults to: {})

    Optional hash for future extensions (currently unused).

Returns:

  • (Mongoid::Criteria)

    A criteria object for the query.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/mongoid/geospatial.rb', line 178

def nearby(coordinates, _options = {})
  if self.spatial_fields.empty?
    raise "No spatial fields defined for #{self.name} to use with .nearby. " \
          "Mark a field with 'spatial: true' or 'sphere: true'."
  end

  field_name_sym = self.spatial_fields.first.to_sym
  field_definition = self.fields[field_name_sym.to_s]

  unless field_definition
    raise "Could not find field definition for spatial field: #{field_name_sym}"
  end

  query_operator = field_definition.options[:sphere] ? :near_sphere : :near

  criteria.where(field_name_sym.send(query_operator) => coordinates)
end

#spatial_index(name, options = {}) ⇒ Object

Creates a 2d spatial index for the given field.

Parameters:

  • name (String, Symbol)

    The name of the field to index.

  • options (Hash) (defaults to: {})

    Additional options for the index.



78
79
80
81
# File 'lib/mongoid/geospatial.rb', line 78

def spatial_index(name, options = {})
  spatial_fields_indexed << name
  index({ name => '2d' }, options)
end

#spatial_scope(field_name, default_geo_near_options = {}) ⇒ Object

Defines a class method to find the closest document to a given point using the specified spatial field via the geoNear command.

Example:

class Place
  include Mongoid::Document
  include Mongoid::Geospatial
  field :location, type: Array
  spherical_index :location # Assumes a 2dsphere index for spherical queries
  spatial_scope :location, spherical: true # Default to spherical for this scope
end

Place.closest_to_location([lon, lat]) # Finds the single closest place
Place.closest_to_location([lon, lat], max_distance: 500) # Override/add options

Parameters:

  • field_name (String, Symbol)

    The name of the spatial field to query.

  • default_geo_near_options (Hash) (defaults to: {})

    Default options for the geoNear command (e.g., ‘{ spherical: true, max_distance: 1000 }`). The key option will be automatically set to field_name.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/mongoid/geospatial.rb', line 115

def spatial_scope(field_name, default_geo_near_options = {})
  method_name    = :"closest_to_#{field_name}"
  field_name_sym = field_name.to_sym
  # key_name       = field_name.to_s # Original geoNear used 'key' for field name

  singleton_class.class_eval do
    define_method(method_name) do |coordinates, additional_options = {}|
      # `coordinates` should be [lon, lat] or a GeoJSON Point hash
      # `self` here is the class (e.g., Bar)

      merged_options = default_geo_near_options.merge(additional_options)

      # Determine if spherical based on options or field definition
      is_spherical = if merged_options.key?(:spherical)
                       merged_options[:spherical]
                     else
                       # self.fields uses string keys for field names
                       field_def = self.fields[field_name.to_s]
                       field_def && field_def.options[:sphere]
                     end
      query_operator = is_spherical ? :near_sphere : :near

      # Prepare the value for the geospatial operator
      # Mongoid::Geospatial::Point.mongoize ensures coordinates are in [lng, lat] array format
      # from various input types (Point object, array, string, hash).
      mongoized_coords = Mongoid::Geospatial::Point.mongoize(coordinates)

      geo_query_value = if merged_options[:max_distance]
                          {
                            # Using $geometry for clarity when $maxDistance is used,
                            # which is standard for $near/$nearSphere operators.
                            "$geometry"    => { type: "Point", coordinates: mongoized_coords },
                            "$maxDistance" => merged_options[:max_distance].to_f
                          }
                        else
                          mongoized_coords # Simple array [lng, lat] for the operator
                        end

      # Start with a base criteria, applying an optional filter query
      current_criteria = merged_options[:query] ? self.where(merged_options[:query]) : self.all

      # Apply the geospatial query. $near and $nearSphere queries return sorted results.
      current_criteria.where(field_name_sym.send(query_operator) => geo_query_value)
    end
  end
end

#spherical_index(name, options = {}) ⇒ Object

Creates a 2dsphere index for the given field, suitable for spherical geometry calculations.

Parameters:

  • name (String, Symbol)

    The name of the field to index.

  • options (Hash) (defaults to: {})

    Additional options for the index.



89
90
91
92
# File 'lib/mongoid/geospatial.rb', line 89

def spherical_index(name, options = {})
  spatial_fields_indexed << name
  index({ name => '2dsphere' }, options)
end