Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find a Location within a stored Circle

I have data in MongoDB representing a Circle as follows:

{
    "_id" : ObjectId("54c1dc6506a4344d697f7675"),
    "location" : [ 
        23.027573, 
        72.50675800000001
    ],
    "radius" : 500
}

I want to query with lat & long to determine whether the location is withing stored lat&long and radius.

I tried following query but unable to execute:

db.test.find({location:{ $geoWithin: { $center: [ [ -74, 40.74 ] ,
                                                         "$radius"] } }})

How can we used stored radius in geoWithin query?

like image 405
Prakash Bhagat Avatar asked Dec 11 '22 01:12

Prakash Bhagat


2 Answers

Even more optimal than the original, you can now use $expr within a $match stage after the initial $geoNear:

db.collection.aggregate([
    { "$geoNear": {
        "near": {
            "type": "Point",
            "coordinates": [ 23.027573, 72.50675800000001 ],
        },
        "distanceField": "distance"
    }},
    { "$match": { "$expr": { "$lte": [ "$distance", "$radius" ] } }}
])

Actually a little more optimal than when first written. Now we can just $redact rather than $project the boolean and $match later:

db.collection.aggregate([
    // Match documents "near" the queried point
    { "$geoNear": {
        "near": {
            "type": "Point",
            "coordinates": [ 23.027573, 72.50675800000001 ],
        },
        "distanceField": "distance"
    }},

    // Calculate if distance is within radius and remove if not
    { "$redact": {
        "$cond": {
            "if": { "$lte": [ "$distance", "$radius" ] },
            "then": "$$KEEP",
            "else": "$$PRUNE"
        }
    }}
])

You've stored the information exactly how you should, but there is a different approach to getting the results than you think.

What you want to use is a $geoNear and specifically the aggregation framework form of that operator. Here's what you do:

db.collection.aggregate([
    // Match documents "near" the queried point
    { "$geoNear": {
        "near": {
            "type": "Point",
            "coordinates": [ 23.027573, 72.50675800000001 ],
        },
        "distanceField": "distance"
    }},

    // Calculate if distance is within radius
    { "$project": {
        "location": 1,
        "radius": 1,
        "distance": 1,
        "within": { "$lte": [ "$distance", "$radius" ] }
    }},

    // Match only documents within the radius
    { "$match": { "within": true } }
])

So that form allows the distance from the queried point to be "projected" in the results, whilst the query will also only return the nearest documents.

Then you use a logical comparison to see if the "distance" value is less than "radius", therefore within the circle.

Finally you match to filter out only those results where that "within" assertion was true.

You can add other options to $geoNear as shown in the documentation. I would also strongly suggest that your storage should also use the GeoJSON format as that is likely to be more compatible to whatever other libraries you might use to work on the results obtained.

like image 72
Neil Lunn Avatar answered Dec 21 '22 23:12

Neil Lunn


MongoDB provides strong support for GEO based query. To check whether your location is within the centre you mentioned, there is a $geoNear.

like image 43
Mayur Avatar answered Dec 21 '22 23:12

Mayur