Mongodb计算符合条件的所有对象中的所有数组元素

aok*_*lov 6 mongodb mongodb-query aggregation-framework

我有一个集合,它是对象的活动日志,如下所示:

{
    "_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")
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

如果我跟随查询:

db.objects.find({
    "createddate": {$gte : ISODate("2015-08-30T00:00:00.000Z")},
    "activity.action" : "test_action"}
    }).count()
Run Code Online (Sandbox Code Playgroud)

它返回包含"test_action"的文档计数(此集合中为3),但我需要计算所有test_actions(此集合中为4).我怎么做?

Bla*_*ven 9

最" $unwind高效"的方法是跳过altogther并简单$group地计算.基本上"过滤"数组得到$size的结果$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]
                    ]
                }
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

MongoDB的未来版本将会$filter更加简单:

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" ]
                        }
                    }
                }
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

使用$unwind会导致文档反规范化并有效地为每个数组条目创建一个副本.在可能的情况下,你应该避免这种情 相比之下,每个文档的过滤和计数数组条目要快得多.由于是一个简单$match$group管道相比,许多阶段.


ZeM*_*oon 6

您可以使用聚合来执行此操作:

db.objects.aggregate([
    {$match: {"createddate": {$gte : ISODate("2015-08-30T00:00:00.000Z")}, {"activity.action" : "test_action"}}},
    {$unwind: "$activity"},
    {$match: {"activity.action" : "test_action"}}},
    {$group: {_id: null, count: {$sum: 1}}}
])
Run Code Online (Sandbox Code Playgroud)

这将产生如下结果:

{
    count: 4
}
Run Code Online (Sandbox Code Playgroud)