Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongodb sort inner array

I've been looking for a while now and can't seem to sort an inner array and keep that in the doc that I'm currently working with.

{
    "service": {
        "apps": {
            "updates": [
              {
                "n" : 1
                "date": ISODate("2012-03-10T16:15:00Z")
              },
              {
                "n" : 2
                "date": ISODate("2012-01-10T16:15:00Z")
              },
              {
                "n" : 5
                "date": ISODate("2012-07-10T16:15:00Z")
              }
            ]
        }
     }
 }

So I want to keep the item to be returned as the service, but have my updates array sorted. So far with the shell I have:

db.servers.aggregate(
        {$unwind:'$service'},
        {$project:{'service.apps':1}},
        {$unwind:'$service.apps'}, 
        {$project: {'service.apps.updates':1}}, 
        {$sort:{'service.apps.updates.date':1}});

Anyone think they can help on this?

like image 226
Ricky Hartmann Avatar asked Mar 13 '13 14:03

Ricky Hartmann


People also ask

How do I sort an array in MongoDB aggregate?

To sort the whole array by value, or to sort by array elements that are not documents, identify the input array and specify 1 for an ascending sort or -1 for descending sort in the sortBy parameter.

Does MongoDB support sorting?

MongoDB can perform sort operations on a single-field index in ascending or descending order. In compound indexes, the sort order determines whether the index can be sorted. The sort keys must be listed in the same order as defined in the index.

How do I sort entries in MongoDB?

To sort documents in MongoDB, you need to use sort() method. The method accepts a document containing a list of fields along with their sorting order. To specify sorting order 1 and -1 are used. 1 is used for ascending order while -1 is used for descending order.


2 Answers

You can do this by $unwinding the updates array, sorting the resulting docs by date, and then $grouping them back together on _id using the sorted order.

db.servers.aggregate(
    {$unwind: '$service.apps.updates'}, 
    {$sort: {'service.apps.updates.date': 1}}, 
    {$group: {_id: '$_id', 'updates': {$push: '$service.apps.updates'}}}, 
    {$project: {'service.apps.updates': '$updates'}})
like image 75
JohnnyHK Avatar answered Oct 15 '22 14:10

JohnnyHK


Starting in Mongo 5.2, it's the exact use case for the new $sortArray aggregation operator:

// {
//   service: { apps: { updates: [
//     { n: 1, date: ISODate("2012-03-10") },
//     { n: 2, date: ISODate("2012-01-10") },
//     { n: 5, date: ISODate("2012-07-10") }
//   ]}}
// }
db.collection.aggregate([
  { $set: {
    "service.apps.updates": {
      $sortArray: {
        input: "$service.apps.updates",
        sortBy: { date: 1 }
      }
    }
  }}
])
// {
//   service: { apps: { updates: [
//     { n: 2, date: ISODate("2012-01-10") },
//     { n: 1, date: ISODate("2012-03-10") },
//     { n: 5, date: ISODate("2012-07-10") }
//   ]}}
// }

This:

  • sorts ($sortArray) the service.apps.updates array (input: "$service.apps.updates")
  • by applying a sort on dates (sortBy: { date: 1 })
  • without having to apply a combination of expensive $unwind, $sort and $group stages
like image 30
Xavier Guihot Avatar answered Oct 15 '22 13:10

Xavier Guihot