Search code examples
mongodbgeolocationmongodb-queryaggregation-framework

$geoNear matching nearest array


I have document in record collection Mongodb (3.4) like below :-

    { 
      "_id" : ObjectId("592d0c78555a7436b0883960"), 
      "userid" : 7, 
       "addresses" : [
        {
            "apporx" : 50.0, 
            "loc" : [
                -73.98137109999999, 
                40.7476039
            ]
        }, 
        {
            "apporx" : 15.0, 
            "loc" : [
                -73.982002, 
                40.74767
            ]          
        }, 
        {
            "apporx" :10.0, 
            "loc" : [
                -73.9819567, 
                40.7471609
            ]
        }
     ]
    }
`

I created index on this collection using below query :- 
`db.records.createIndex({'addresses.loc':1})`

when i execute my below query :-
`db.records.aggregate( 
      {$geoNear : {
        near : [ -73.9815103, 40.7475731 ],
        distanceField: "distance" 
    }});

this result gives me distance field.now can you explain me in my document which address array in this multiple elements exists. how can i determine for which element this result true?

Another question :- if i make condition on "addresses.apporx" like greater then or equal then is there any way to find location of this condition?


Solution

  • Firstly I strongly advise that you create a "2dsphere" index for your collection if you intend to to geospatial queries on real world coordinates.

    Make sure to drop other indexes you may have been playing with:

    db.records.dropIndexes();
    db.records.createIndex({ "addresses.loc": "2dsphere" })
    

    In order to do what you want, first take a look at the slight modification that also includes the includeLocs option to $geoNear

    db.records.aggregate([
      { "$geoNear": {
         "near": [ -73.9815103, 40.7475731 ],
         "spherical": true,
         "distanceField": "distance",
         "includeLocs": "locs"
      }}
    ])
    

    Now you will see output that looks like this:

    {
            "_id" : ObjectId("592d0c78555a7436b0883960"),
            "userid" : 7,
            "addresses" : [
                    {
                            "apporx" : 50,
                            "loc" : [
                                    -73.98137109999999,
                                    40.7476039
                            ]
                    },
                    {
                            "apporx" : 15,
                            "loc" : [
                                    -73.982002,
                                    40.74767
                            ]
                    },
                    {
                            "apporx" : 10,
                            "loc" : [
                                    -73.9819567,
                                    40.7471609
                            ]
                    }
            ],
            "distance" : 0.0000019174641401278624,
            "locs" : [
                    -73.98137109999999,
                    40.7476039
            ]
    }
    

    So what that returned was not only the distance to the point that was nearest but "which" location was the match used.

    So if you wanted to $filter the original array to return the nearest, then you can:

    db.records.aggregate([
      { "$geoNear": {
         "near": [ -73.9815103, 40.7475731 ],
         "spherical": true,
         "distanceField": "distance",
         "includeLocs": "locs"
      }},
      { "$addFields": {
        "addresses": {
          "$filter": {
            "input": "$addresses",
            "as": "address",
            "cond": { "$eq": [ "$$address.loc", "$locs" ] }
          }
        }
      }}
    ])
    

    And that returns the array with only that match:

    {
            "_id" : ObjectId("592d0c78555a7436b0883960"),
            "userid" : 7,
            "addresses" : [
                    {
                            "apporx" : 50,
                            "loc" : [
                                    -73.98137109999999,
                                    40.7476039
                            ]
                    }
            ],
            "distance" : 0.0000019174641401278624,
            "locs" : [
                    -73.98137109999999,
                    40.7476039
            ]
    }