Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongodb aggregate (count) on multiple fields simultaneously

Tags:

I've got documents that look like this:

{     "_id" : "someuniqueeventid",     "event" : "event_type_1",     "date" : ISODate("2014-01-14T00:00:00Z"), } 

I want to group by "event" and count how many of each event type occured in each day of the week. Basically, I want to get something like:

{     "_id": "event_type_1",     "1": "number of event_type_1 for Monday",     "2": "number of event_type_1 for Tuesday",     ... }, {     "_id": "event_type_2",     ... } 

Unfortunately, I'm stuck at:

db.data.aggregate([ {$project: {date_of_week: {$dayOfWeek: "$date"}, event: "$event"}},                      {$group: {_id: "$event", .... } ]) 

Any ideas?

like image 247
Unknown Avatar asked Sep 15 '14 07:09

Unknown


People also ask

Can we specify more than one aggregate function simultaneously in MongoDB?

Mongodb group by multiple fields using Aggregate operation First, the key on which the grouping is based is selected and then the collection is divided into groups according to the selected key value. You can then create a final document by aggregating the documents in each group.

Can we use count with aggregate function in MongoDB?

The MongoDB $count operator allows us to pass a document to the next phase of the aggregation pipeline that contains a count of the documents. There a couple of important things to note about this syntax: First, we invoke the $count operator and then specify the string.

Can we use two group by in same query in MongoDB?

Yes the listings have more than two $group stages, the heavy lifting is actually done in two groupings with the others just there for array manipulation if you require it, but it gives you exact and ordered results.


1 Answers

The aggregation framework won't create keys based on data, nor should you even be doing so as "data" is not a key but actually data, so you should stick to the pattern.

That means you can basically just do this:

db.data.aggregate([     { "$group": {         "_id": {             "event_type": "$event",             "day": { "$dayOfWeek": "$date" }         },         "count": { "$sum": 1 }      }} ]) 

And that will count the occurrences per day of week per event, albeit in multiple documents in the output, but this is easy to change to a single document per event:

db.data.aggregate([     { "$group": {         "_id": {             "event_type": "$event",             "day": { "$dayOfWeek": "$date" }         },         "count": { "$sum": 1 }      }},     { "$group": {         "_id": "$_id.event_type",         "days": { "$push": { "day": "$_id.day", "count": "$count" } }     }} ]) 

And that is in an array form, but it still holds the results you want.

If you are really bent on doing your exact form then you want to do something like this:

db.data.aggregate([     { "$group": {         "_id": "$event",         "1": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 1 ] },                     1,                     0                 ]             }         },         "2": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 2 ] },                     1,                     0                 ]             }         },         "3": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 3 ] },                     1,                     0                 ]             }         },         "4": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 4 ] },                     1,                     0                 ]             }         },         "5": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 5 ] },                     1,                     0                 ]             }         },         "6": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 6 ] },                     1,                     0                 ]             }         },         "7": {             "$sum": {                 "$cond": [                     { "$eq": [{ "$dayOfWeek": "$date" }, 7 ] },                     1,                     0                 ]             }         }     }} ) 

But that is really long winded so IMHO I would stick with the first or maybe second solution as they are shorter and more easy to read.

like image 109
Neil Lunn Avatar answered Oct 12 '22 07:10

Neil Lunn