Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongo aggregation field x with max y

I have a collection of documents, e.g.:

{_id: 1, kind: 'cow', nickname: 'bess', weight: 145}
{_id: 2, kind: 'cow', nickname: 'babs', weight: 130}
{_id: 3, kind: 'horse', nickname: 'boris', weight: 140}
{_id: 4, kind: 'horse', nickname: 'gnoris', weight: 110}

I'd like to group them by the 'kind' field, and then return the nickname of the animal with the largest weight in each group, the max weight in the group, and the number of animals in the group, thus returning:

{'kind': 'cow', 'nickname': 'bess', 'max_weight': 145, 'count': 2}
{'kind': 'horse', 'nickname': 'boris', 'max_weight': 140, 'count': 2}

I can see how to return the max weight and count for each group with the following mongo aggregation:

db.aggregate([
    {'$group': {'_id': '$kind',
                'max_weight': {'$max': '$weight'},
                'count': {'$sum': 1}}}
])

Is there a way to have this aggregation return the corresponding nickname for the heaviest animal in each group?

like image 447
nonagon Avatar asked Jul 24 '15 16:07

nonagon


People also ask

How do you use limits in aggregation?

Answer: $skip before $limit In aggregate, $limit limits the number of documents sent to the next aggregation state, and $skip skips the first N documents, so if $skip is after $limit and $skip >= $limit, you won't get any results.

How can you group by a particular value in MongoDB?

We can group by single as well as multiple field from the collection, we can use $group operator in MongoDB to group fields from the collection and returns the new document as result. We are using $avg, $sum, $max, $min, $push, $last, $first and $addToSet operator with group by in MongoDB.

How do I limit in MongoDB?

The Limit() Method To limit the records in MongoDB, you need to use limit() method. The method accepts one number type argument, which is the number of documents that you want to be displayed.


1 Answers

Use $sort instead of $max to return a whole document and reference with $first:

db.collection.aggregate([
    { "$sort": { "weight": -1 } },
    { "$group": {
         "_id": "$kind", 
         "max_weight": { "$first": "$weight" },
         "nickname": { "$first": "$nickname" },
         "count": { "$sum": 1 }
    }}
])

That makes sure the document values on the "grouping boundary" is returned by the arguments you give to $first. Since $sort is in descending order of "weight".

like image 52
Blakes Seven Avatar answered Nov 15 '22 04:11

Blakes Seven