MongoDB sort documents by array elements

You cannot do that with arrays, and the main problem here is because you want the “sort” to happen on the matched element. If you want to sort results like this then you need to use .aggregate() instead. Either as:

For modern MongoDB versions:

db.maps.aggregate([
    { "$match": { "points.type": "type1" }},
    { "$addFields": {
        "order": {
            "$filter": {
              "input": "$points",
              "as": "p",
              "cond": { "$eq": [ "$$p.type", "type1" ] }
            }
        }
    }},
    { "$sort": { "order": 1 } }
])

For MongoDB 2.6 to 3.0

db.maps.aggregate([
   { $match: { 'points.type': 'type1' } },
    {
     $project: {
       points: {
        $setDifference: [
          {
            $map: {
              input: '$points',
              as: 'p',
              in: {
                $cond: [
                  { $eq: ['$$p.type', 'type1'] },
                  '$$p',
                  false,
                ]
              }
            }
          },
          [false]
        ]
      }
    }
  },
  { $sort: { 'points.distanceToSpawn': 1 } },
]);

Or less efficiently in versions prior to MongoDB 2.6:

db.maps.aggregate([
    { "$match": { "points.type": "type1" }},
    { "$unwind": "$points" },
    { "$match": { "points.type": "type1" }},
    { "$group": {
        "_id": "$_id",
        "points": { "$push": "$points" }
    }},
    { "$sort": { "points.ditanceToSpawn": 1 } }         
])

That’s the only way to match the correct elements and have them considered in a “sort” operation. The default cursor sort will just otherwise consider the values for the field in the array elements that do not match your selected “type” instead.

Leave a Comment