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

Popular posts from this blog

c# - Binding a comma separated list to a List<int> in asp.net web api -

Delphi 7 and decode UTF-8 base64 -

html - Is there any way to exclude a single element from the style? (Bootstrap) -