'Sort array of objects, using values inside each object (aggregation framework)

Suppose I have these documents:

[
  {
    '_id': 1,
    'roles': [
      {
        'k': 'free',
        'v': 1
      },
      {
        'k': 'pro',
        'v': 5
      },
      {
        'k': 'free',
        'v': 2
      }
    ]
  },
  {
    '_id': 2,
    'roles': [
      {
        'k': 'pro',
        'v': 1
      },
      {
        'k': 'free',
        'v': 3
      },
      {
        'k': 'free',
        'v': 2
      }
    ]
  }
]

So for every _id, we have a array of documents called roles.
I need to sort inside the array roles, using the v field.

Expected output:

[
  {
    '_id': 1,
    'roles': [
      {
        'k': 'free',
        'v': 1
      },
      {
        'k': 'free',
        'v': 2
      }
      {
        'k': 'pro',
        'v': 5
      }
    ]
  },
  {
    '_id': 2,
    'roles': [
      {
        'k': 'pro',
        'v': 1
      },
      {
        'k': 'free',
        'v': 2
      }
      {
        'k': 'free',
        'v': 3
      }
    ]
  }
]

So I tried to use $sort:

{
  '$sort': {
     'roles.v': 1
  }
}

But it does not sort inside the array.



Solution 1:[1]

You need to $unwind and $group to reconstruct.

([
  { $unwind: "$roles" },
  { $sort: { "roles.v": 1 }},
  { $group: {
    _id: "$_id",
    roles: { $push: "$roles" }
  }}
])

Solution 2:[2]

In order to sort by _id and if $project is needed, this will work as well.

db.getCollection("collectionName").aggregate([
    { $unwind: "$roles" },
    { $sort: { "roles.v": 1 }},
    { $group: {
        _id: "$_id",
        roles: { $push: "$roles" }
    }},
    {$project: {
        _id: "$_id",
        roles: "$roles"
    }},
    {$sort: {"_id": 1}}
])

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ashh
Solution 2