MongoDB query : $near with aggregation

aggregation-framework, mongodb

Solution

You will have to use $geoNear, and only if you are using V2.4 onward

db.users.aggregate(   
    {$geoNear : {
        near: [-1, -2],
        distanceField: "distance",
        query : {"_id" : "id1"},
        uniqueDocs: true,
        maxDistance : 2000
}})

Edit : after edit to question

The bellow query will give you location and distance, but doesn't retrieve the internal (array element) _id

db.users.aggregate(   
  {$geoNear : {
    near: [-1, -2],
    distanceField: "distance",
    includeLocs: "location",
    query : {"_id" : "id1"},
    maxDistance : 2000
  }},
  {$project : {"location" : 1, "_id" : 0, "distance" : 1}} 
)

Note the addition of `includeLocs` and elimination of `uniqueDocs: true`

To also retrieve the internal _id, you will have to (following this example) unwind and conditionally project or so, but I don't think it worth it, unless you need the address instead of the _id

Problem

I have a collection that looks like that ``` { "_class" : "User", "_id" : "id1", "places" : [ { "_id" : "1", "address" : "test1", "location" : { "latitude" : 1, "longitude" : 1 } }, { "_id" : "2", "address" : "test2", "location" : { "latitude" : 2, "longitude" : 2 } },... ] } ``` I am trying to retrieve every place of a user (in a range of 2 km). This query doesn't work : ``` db.users.ensureIndex({"places.location":"2d"}) db.users.aggregate([ {$match : { "_id" : "id1" } }, {$unwind : "$places"}, {$project:{_id:0, places:1}, {$match : {"places.location" : { $near : { $geometry : { type : "2d" , coordinates : [ -1 , -2 ] } }, $maxDistance : 2000 } } }]) Error: Printing Stack Trace at printStackTrace (src/mongo/shell/utils.js:37:15) at DBCollection.aggregate (src/mongo/shell/collection.js:897:9) at (shell):1:10 JavaScript execution failed: aggregate failed: { "errmsg" : "exception: $near is not allowed inside of a $match aggregation expression", "code" : 16424, "ok" : 0 ``` I don't know how to use $near with aggregation. When i try ``` db.users.find( { "places.location" : { $near: { $geometry : { type : "2d" , coordinates : [ -1 , -2 ] } }, $maxDistance : 2000 } } ``` It returns me n times the given user (n = each place of the user), this is why i have decided to use aggregation, but i'm stuck. Thx in advance EDIT I tried $geoNear : ``` db.users.aggregate( {$geoNear : { near: [-1, 1], distanceField: "distance", query : {"_id" : "id1"}, uniqueDocs: true, maxDistance : 2000 // In the specs, distance has to be in radians }}) ``` and it returns me the whole user (with all the places, even the far ones). So I need to rework the document before I search for the correct places. - Retrieve the correct user (match) - Unwind every places of the user - then search every place in a range of 2 km (near/geonear) - reshape the result (project) The result I am expecting is something like : ``` "result" : [ { "_id" : "1", "location" : { "latitude" : 1, "longitude" : 1 } }, { "_id" : "2", "location" : { "latitude" : 2, "longitude" : 2 } } ]} ``` The problem is that I can't use other stages before $geoNear, my search parameters have to be specified in the "query" field. I get the following error : ``` $geoNear is only allowed as the first pipeline stage ```

Original source