Mongodb sort array inside array of embedded documents

Viewed 409

I have the following collection

[{
  _id: 1
  "origins": [
    {
        'depth': 100,
        'magnitudes': [
            { 'magval': 5 }, { 'magval': 6 }, { 'magval': 7 }
         ]
    },
    {
        'depth': 90,
        'magnitudes': [
            { 'magval': 5 }, { 'magval': 6 }, { 'magval': 7 }
         ]
    }
  ]
},
{
  _id: 2
  "origins": [
    {
        'depth': 100,
        'magnitudes': [
            { 'magval': 5 }, { 'magval': 6 }, { 'magval': 7 }
         ]
    },
    {
        'depth': 90,
        'magnitudes': [
            { 'magval': 5 }, { 'magval': 6 }, { 'magval': 7 }
         ]
    }
  ]
}

Using a query such as this (pymongo) :

collection.update(
        {},
        {
            '$push': {
                'origins': {
                    '$each': [],
                    '$sort': {'depth': -1}
                }
            }
        }, multi=True, upsert=True
    )

... I can update my collection in place so that the embedded array of origins becomes sorted in descending order by the depth field.

Question is ... how do I perform a similar in-place sort on the embedded array of magnitude objects that is a child of each origin object ? I would like that the magnitudes inside the origins become sorted by magval, descending.

Final output should be stored back in the database like so:

{
  "origins": [
    {
        'depth': 100,
        'magnitudes': [
            { 'magval': 7 }, { 'magval': 6 }, { 'magval': 5 }
         ]
    },
    {
        'depth': 90,
        'magnitudes': [
            { 'magval': 7 }, { 'magval': 6 }, { 'magval': 5 }
         ]
    }
  ]
}
1 Answers

In MongoDB v3.6 you can use array update operators $[ ]. This operator indicates that the update operator should modify all elements in the specified array field.

Using your example documents, i.e. :

db.collection.update({}, 
                     {
                      "$push": {
                                "origins.$[].magnitudes":{
                                                          $each:[], 
                                                          $sort:{ "magval": -1 }
                                                         }
                               }
                     }, 
                     {"multi":true, "upsert":true}
)

Having said that, please re-consider your data modelling approach; storing values within array of arrays may create difficulty in querying/updating.

Related