简体   繁体   中英

How To Sort mongodb query results based on subdocuments

i am having 2 documents in score collections(student)databases like below in mongodb database.

{ 
    id: 2, 
    type: 'newname', 
    subs: [
        { time: 20, val: 'b' },
        { time: 12, val: 'a' },
        { time: 30, val: 'c' }
    ] }, { 
    id: 1, 
    type: 'strs', 
    subs: [
        { time: 50, val: 'be' },
        { time: 1, val: 'ab' },
        { time: 20, val: 'cs' }
    ] }

How to construct a query to get the below result

{ 
    id: 1, 
    type: 'strs', 
    subs: [
        { time: 1, val: 'ab' },
        { time: 20, val: 'cs' },
        { time: 50, val: 'be' }
    ]
},
{ 
    id: 2, 
    type: 'newname', 
    subs: [
        { time: 12, val: 'a' },
        { time: 20, val: 'b' },
        { time: 30, val: 'c' }
    ]
}

ie: a query for find the documents based on time and have to sort the results on 2 criteria

  1. by id ASC
  2. by sub document time ASC

You can use cursor.sort() to sort on multiple fields (basically a combo) at the same time but I don't think it works when sorting on both a document and a subdocument field at the same time. If you were to sort on two different fields of the top document or on two different fields of a subdocument then it would be fine i guess.

So you can get a similar output using the aggregation framework. All you have to do is basically break down the arrays of the subs field and then sort them.

You could do something like:

db.col.aggregate({$unwind:'subs'}, {$sort:{id:1,'subs.time':1}});

With the above code you should get an output similar to this:

 { 
    id: 1, 
    type: 'strs', 
    subs: 
        { time: 1, val: 'ab' }
},{ 
    id: 1, 
    type: 'strs', 
    subs: 
        { time: 20, val: 'cs' }
},{ 
    id: 1, 
    type: 'strs', 
    subs: 
        { time: 50, val: 'be' }
},{ 
    id: 2, 
    type: 'newname', 
    subs: 
        { time: 12, val: 'a' }
},{ 
    id: 2, 
    type: 'newname', 
    subs: 
        { time: 20, val: 'b' }
},{ 
    id: 2, 
    type: 'newname', 
    subs: 
        { time: 30, val: 'c' }
}

Strangely, MongoDB does not provide any method to sort sub documents by querying it. It seems you will have to update the natural sort order of the sub docs as shown below :

If these are the only 2 docs in your collection, write below query :

db.test.update( {}, {$push : {"subs" :{$each  : [] , $sort : {time : -1}}}})

and then run query to sort on ID itself :

db.test.find().sort({'id':1}).pretty()

You will get below output.

{                                                             

        "id" : 1,                                             
        "type" : "strs",                                      
        "subs" : [                                            
                {                                             
                        "time" : 50,                          
                        "val" : "be"                          
                },                                            
                {                                             
                        "time" : 20,                          
                        "val" : "cs"                          
                },                                            
                {                                             
                        "time" : 1,                           
                        "val" : "ab"                          
                }                                             
        ]                                                     
}                                                             
{                                                             

        "id" : 2,                                             
        "type" : "newname",                                   
        "subs" : [                                            
                {                                             
                        "time" : 30,                          
                        "val" : "c"                           
                },                                            
                {                                             
                        "time" : 20,                          
                        "val" : "b"                           
                },                                            
                {                                             
                        "time" : 12,                          
                        "val" : "a"                           
                }                                             
        ]                                                     
}     

Hope it solves you situation. Below is the reference :

http://docs.mongodb.org/manual/reference/operator/update/sort/#sort-array-of-documents-by-a-field-in-the-documents

It is possible when use in sequence $unwind > $sort > $group specialty for array,

db.collection.aggregate([
  { $unwind: "$subs" },
  • $sort subs.time in ascending (1) order
  { $sort: { "subs.time": 1 } },
  • $group by id , and re-construct subs array using $push objects and other fields remain using $first
  {
    $group: {
      _id: "$id",
      id: { $first: "$id" },
      type: { $first: "$type" },
      subs: { $push: "$subs" }
    }
  },
  { $project: { _id: 0 } },
  • $sort by id in ascending order
  { $sort: { id: 1 } }
])

Playground

You can use cursor.sort(sort)

For Exapmle:

db.collection.find().sort( { 'id': 1 } )

to sort the results using id in ascending order.

For more details refer the following link.http://docs.mongodb.org/manual/reference/method/cursor.sort/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM