Find Mongoid geospacial circles that contain a point

185 views Asked by At

I have Mongoid documents that represent services offered by local merchants. Each has one or more locations (lat/lng point) with a service area (radius). Given a customer location (lat/lng point), how can I find all the documents where the customer location falls within the service area?

class Service
  include Mongoid::Document

  # Data currently stored like this:
  field :address, type: String
  field :service_distance, type: Float

  # Happy to geocdoe and store in another format
end    

Most examples are based are searching for points within a circle (where the radius is part of the query and the same for all documents) not finding circles that intersect a point (where the circles have different radii).

1

There are 1 answers

0
AudioBubble On BEST ANSWER

Modelling a "circle" is a valid approach by specifying a "centre" and a "radius", but finding things "within the circle" is generally straightforward if not immediately obvious:

Service.collection.aggregate([

    # Get the distance from the current location
    { "$geoNear" => {
        "near" => {
           "type" => "Point",
           "coordinates" => [ 1, 1 ] 
        },
        "distanceField" => "dist"
    }},

    # Find out if the "dist" is within the radius
    { "$project" => {
        "address" => 1,
        "service_distance" =>1,
        "location" => 1,  # the field with the co-ordinates you add
        "dist" => 1,
        "within" => { "$lt" => [ "$dist", "$service_distance" ] }
    }},

    # Then filter out anything not "within"
    { "$match" => { "within" => true } }

])

So the $geoNear aggregation operator not only finds documents "near" the specified point but also "projects" a field into the document that represents the "distance" from that point in the query.

Note the "extra field" you asked for here ( "location" ) is the actual "co-ordinates" of the "Point" for the center of the circle where the "shop" is located. That's the additional field required here.

The next thing to do is "compare" the calculated distance to the "radius" or "service_distance" contained in the document and see if it is "less than" or "within" that distance.

Then, where that result is true you keep those documents and present them in your final response.

The .collection accessor here allows you to use native MongoDB methods such as .aggregate() which allows these sort of operations.

So that is how you do it in server processing.