Mongodb计算所有按条件匹配的对象中的所有数组元素

标签 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")
        }
    ]
}

如果我进行以下查询:

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

它返回包含“test_action”的文档计数(本集中 3 个),但我需要获取所有 test_actions 的计数(本集中 4 个)。我该怎么做?

最佳答案

最“高效”的方法是跳过 $unwind总而言之$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]
                    ]
                }
            }
        }
    }}
])

从 MongoDB 3.2 版开始,我们可以使用 $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" ]
                        }
                    }
                }
            }
        }
    }}
])

使用 $unwind 会导致文档去规范化并有效地为每个数组条目创建一个副本。在可能的情况下,您应该避免这种情况,因为这通常会带来极高的成本。相比之下,过滤和计算每个文档的数组条目要快得多。与许多阶段相比,简单的 $match$group 管道也是如此。

关于Mongodb计算所有按条件匹配的对象中的所有数组元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32305897/

相关文章:

Haskell 不明确的类型变量——我迷路了?

mongodb - time.Duration 出乎意料地是 'divided' by 1'000' 000

mongodb - mongodump 错误 "Failed: can' t 创建 session : could not connect to server:"

MongoDB 聚合框架 : group query

mongodb - 如何使用mongo聚合计算不同文档值之间的差异?

java - "PersistentEntity must not be null"MongoDB 和 Spring Data REST 异常

php - 如何使 "LIKE"查询在 MongoDB 中工作?

MongoDB GROUP BY 和 COUNT 未知键

spring - 从 Spring/MongoDB findAndModify 返回新旧实体

Mongodb聚合框架|双赛