The most βefficientβ way to do this is to skip $unwind altogther and just $group to count. Essentially, filter arrays get $size results $sum :
db.objects.aggregate([ { "$match": { "createddate": { "$gte": ISODate("2015-08-30T00:00:00.000Z") }, "activity.action": "test_action" }}, { "$group": { "_id": null, "count": { "$sum": { "$size": { "$setDifference": [ { "$map": { "input": "$activity", "as": "el", "in": { "$cond": [ { "$eq": [ "$$el.action", "test_action" ] }, "$$el", false ] } }}, [false] ] } } } }} ])
Future releases of MongoDB will have $filter , which makes this a lot easier:
db.objects.aggregate([ { "$match": { "createddate": { "$gte": ISODate("2015-08-30T00:00:00.000Z") }, "activity.action": "test_action" }}, { "$group": { "_id": null, "count": { "$sum": { "$size": { "$filter": { "input": "$activity", "as": "el", "cond": { "$eq": [ "$$el.action", "test_action" ] } } } } } }} ])
Using $unwind forces documents to de-normalize and efficiently create a copy to write to the array. Where possible, you should avoid this because of too high a cost. Filtering and counting array entries per document is much faster. As a simple pipeline $match and $group compared to many stages.
source share