Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongo order by length of array

Lets say I have mongo documents like this:

Question 1

{
    answers:[
       {content: 'answer1'},
       {content: '2nd answer'}
    ]
}

Question 2

{
    answers:[
       {content: 'answer1'},
       {content: '2nd answer'}
       {content: 'The third answer'}
    ]
}

Is there a way to order the collection by size of answers?

After a little research I saw suggestions of adding another field, that would contain number of answers and use it as a reference but may be there is native way to do it?

like image 991
Evgenius Avatar asked Jan 27 '12 21:01

Evgenius


People also ask

How do I sort an array length in MongoDB?

you can use mongodb aggregation stage $addFields which will add extra field to store count and then followed by $sort stage. Show activity on this post. You can use $size attribute to order by array length.

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.

How do I get the length of a field in MongoDB?

As for the logical condition, there are String Aggregation Operators that you can use $strLenCP operator to check the length of the string. If the length is $gt a specified value, then this is a true match and the document is "kept".


2 Answers

I thought you might be able to use $size, but that's only to find arrays of a certain size, not ordering.

From the mongo documentation: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24size

You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements. Indexes cannot be used for the $size portion of a query, although if other query expressions are included indexes may be used to search for matches on that portion of the query expression.

Looks like you can probably fairly easily do this with the new aggregation framework, edit: which isn't out yet. http://www.mongodb.org/display/DOCS/Aggregation+Framework

Update Now the Aggregation Framework is out...

> db.test.aggregate([
  {$unwind: "$answers"}, 
  {$group: {_id:"$_id", answers: {$push:"$answers"}, size: {$sum:1}}}, 
  {$sort:{size:1}}]);
{
"result" : [
    {
        "_id" : ObjectId("5053b4547d820880c3469365"),
        "answers" : [
            {
                "content" : "answer1"
            },
            {
                "content" : "2nd answer"
            }
        ],
        "size" : 2
    },
    {
        "_id" : ObjectId("5053b46d7d820880c3469366"),
        "answers" : [
            {
                "content" : "answer1"
            },
            {
                "content" : "2nd answer"
            },
            {
                "content" : "The third answer"
            }
        ],
        "size" : 3
    }
  ],
  "ok" : 1
}
like image 176
Eve Freeman Avatar answered Oct 23 '22 04:10

Eve Freeman


I use $project for this:

db.test.aggregate([
    {
        $project : { answers_count: {$size: { "$ifNull": [ "$answers", [] ] } } }
    }, 
    {   
        $sort: {"answers_count":1} 
    }
])

It also allows to include documents with empty answers. But also has a disadvantage (or sometimes advantage): you should manually add all needed fields in $project step.

like image 46
Oleg Avatar answered Oct 23 '22 06:10

Oleg