Mongodb count all array elements in all objects matching by criteria -
i have collection log of activity on objects this:
{ "_id" : objectid("55e3fd1d7cb5ac9a458b4567"), "object_id" : "1", "activity" : [ { "action" : "test_action", "time" : isodate("2015-08-31t00:00:00.000z") }, { "action" : "test_action", "time" : isodate("2015-08-31t00:00:22.000z") } ] } { "_id" : objectid("55e3fd127cb5ac77478b4567"), "object_id" : "2", "activity" : [ { "action" : "test_action", "time" : isodate("2015-08-31t00:00:00.000z") } ] } { "_id" : objectid("55e3fd0f7cb5ac9f458b4567"), "object_id" : "1", "activity" : [ { "action" : "test_action", "time" : isodate("2015-08-30t00:00:00.000z") } ] }
if followoing query:
db.objects.find({ "createddate": {$gte : isodate("2015-08-30t00:00:00.000z")}, "activity.action" : "test_action"} }).count()
it returns count of documents containing "test_action" (3 in set), need count of test_actions (4 on set). how do that?
the "performant" way skip $unwind
altogther , $group
count. "filter" arrays $size
of 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 have $filter
, makes more simple:
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
causes documents de-normalize , creates copy per array entry. possible should avoid due the extreme cost. filtering , counting array entries per document faster comparison. simple $match
, $group
pipeline compared many stages.
Comments
Post a Comment