Mongoose Geo Near Search - How to sort within a given distance? Mongoose Geo Near Search - How to sort within a given distance? mongoose mongoose

Mongoose Geo Near Search - How to sort within a given distance?


In find query you need to use location instead of location.coordinates.

router.get("/test", async (req, res) => {  const lat = 59.9165591;  const lng = 10.7881978;  const maxDistanceInMeters = 1000;  const result = await model    .find({      location: {        $near: {          $geometry: {            type: "Point",            coordinates: [lng, lat],          },          $maxDistance: maxDistanceInMeters,        },      },    })    .sort("-score");  res.send(result);});

For $near to work you need an 2dsphere index on the related collection:

db.collection.createIndex( { "location" : "2dsphere" } )

In mongodb $near docs it says:

$near sorts documents by distance. If you also include a sort() for the query, sort() re-orders the matching documents, effectively overriding the sort operation already performed by $near. When using sort() with geospatial queries, consider using $geoWithin operator, which does not sort documents, instead of $near.

Since you are not interested in sorting by distance, as Nic indicated using $near is unnecessary, better to use $geoWithin like this:

router.get("/test", async (req, res) => {  const lat = 59.9165591;  const lng = 10.7881978;  const distanceInKilometer = 1;  const radius = distanceInKilometer / 6378.1;  const result = await model    .find({      location: { $geoWithin: { $centerSphere: [[lng, lat], radius] } },    })    .sort("-score");  res.send(result);});

To calculate radius we divide kilometer to 6378.1, and miles to 3963.2 as described here.

So this will find the locations inside 1km radius.

Sample docs:

[    {        "location": {            "type": "Point",            "coordinates": [                10.7741692,                59.9262198            ]        },        "score": 50,        "_id": "5ea9d4391e468428c8e8f505",        "name": "Name1"    },    {        "location": {            "type": "Point",            "coordinates": [                10.7736078,                59.9246991            ]        },        "score": 70,        "_id": "5ea9d45c1e468428c8e8f506",        "name": "Name2"    },    {        "location": {            "type": "Point",            "coordinates": [                10.7635027,                59.9297932            ]        },        "score": 30,        "_id": "5ea9d47b1e468428c8e8f507",        "name": "Name3"    },    {        "location": {            "type": "Point",            "coordinates": [                10.7635027,                59.9297932            ]        },        "score": 40,        "_id": "5ea9d4971e468428c8e8f508",        "name": "Name4"    },    {        "location": {            "type": "Point",            "coordinates": [                10.7768093,                59.9287668            ]        },        "score": 90,        "_id": "5ea9d4bd1e468428c8e8f509",        "name": "Name5"    },    {        "location": {            "type": "Point",            "coordinates": [                10.795769,                59.9190384            ]        },        "score": 60,        "_id": "5ea9d4e71e468428c8e8f50a",        "name": "Name6"    },    {        "location": {            "type": "Point",            "coordinates": [                10.1715157,                59.741873            ]        },        "score": 110,        "_id": "5ea9d7d216bdf8336094aa92",        "name": "Name7"    }]

Output: (within 1km and sorted by descending score)

[    {        "location": {            "type": "Point",            "coordinates": [                10.7768093,                59.9287668            ]        },        "score": 90,        "_id": "5ea9d4bd1e468428c8e8f509",        "name": "Name5"    },    {        "location": {            "type": "Point",            "coordinates": [                10.7736078,                59.9246991            ]        },        "score": 70,        "_id": "5ea9d45c1e468428c8e8f506",        "name": "Name2"    },    {        "location": {            "type": "Point",            "coordinates": [                10.795769,                59.9190384            ]        },        "score": 60,        "_id": "5ea9d4e71e468428c8e8f50a",        "name": "Name6"    },    {        "location": {            "type": "Point",            "coordinates": [                10.7741692,                59.9262198            ]        },        "score": 50,        "_id": "5ea9d4391e468428c8e8f505",        "name": "Name1"    }]


$near sorts documents by distance which is a waste here. It's probably better to use $geoWithin which does not sort documents. Something like:

model.find({  "location.coordinates": {      $geoWithin: { $center: [ [-74, 40.74], <radius> ] } } }).sort({score: -1});

The $center docs have some more details.