The closest working solution I've got is the following aggregation:
[
{
$facet: {
a: [
{ $unwind: '$a' },
{ $sort: { a: 1 } },
{
$group: {
_id: '$_id',
a: { $push: '$a' }
}
}
],
b: [
{ $unwind: '$b' },
{ $sort: { b: 1 } },
{
$group: {
_id: '$_id',
b: { $push: '$b' }
}
}
],
c: [
{ $unwind: '$c' },
{ $sort: { c: 1 } },
{
$group: {
_id: '$_id',
c: { $push: '$c' }
}
}
]
}
},
{
$set: {
a: { $arrayElemAt: ['$a.a', 0] },
b: { $arrayElemAt: ['$b.b', 0] },
c: { $arrayElemAt: ['$c.c', 0] }
}
}
]
In short, what this does is: $facet
performs identical operations on each a
, b
, c
field in parallel; each field is split with $unwind
, sorted in ascending order and then grouped on itself.
Until this point we already have sorted fields but each field is now an object with appropriate name (for example, { _id: '', a: [...] }
). So, to return to the array we had earlier, another stage is to simply extract only the needed field from each object. This is done with $set
and $arrayElemAt
(which takes first array field).
So, in the end we have each field sorted in ascending order while having the same amount of documents.
Note: this only works if you have a single result document. If you have multiple of them, then you will need to slightly change stages:
$facet
stage remains the same
- Updated
$set
(second) stage is changed to:
Use $unwind
+ updated $set
stages for each separate field (in this case, we have a
, b
, c
):
{ $unwind: '$a' },
{ $unwind: '$b' },
{ $unwind: '$c' },
{ $set: { a: '$a.a' } },
{ $set: { b: '$b.b' } },
{ $set: { c: '$c.c' } }
This might not be the prettiest approach but I could not find shorter version.