【问题标题】:How to calculate a sum of specific documents using aggregation?如何使用聚合计算特定文档的总和?
【发布时间】:2016-02-06 19:11:26
【问题描述】:

我有一个表示消息线程的架构。所以 mongo 数据库中的每个文档看起来像这样:

{
    id: "thread_id",
    participants: ["user1", "user2"],
    unReadMessageCounts: [
         {
             participant: "user1",
             count: 5
         },
         {
             participant: "user2",
             count: 3
         }
}

我想要做的是获取给定用户的所有未读消息计数的总和 - 例如,“user2”。我知道我可以通过在集合上执行find() 然后编写一个函数来总结给定用户的计数来做到这一点。但如果可能的话,我想使用 mongo 的 aggregate 功能。我知道我可以做一个match 来首先选择“user2”是参与者的所有线程,但是我如何构造group 和/或sum 表达式以从文档中提取正确的字段?

【问题讨论】:

  • 公平点。在我的情况下,开始的文件数量并不是很大,所以@chridam 回答的简短程度略有增加,这对我来说更可取。但我也赞成你的回答,因为它确实是一个完美的解决方案。

标签: mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

使用以下聚合管道来获得所需的结果。初始步骤通过 $match 运算符过滤掉传入的文档以仅接受 "user2" 参与者。

然后,前面的管道阶段通过 $unwind 运算符“非规范化”unReadMessageCounts 数组,该运算符从数组中为每个现有文档(在您的上述示例数据中)输出 2 个文档。

需要进一步过滤才能为正确的参与者聚合数据,这是通过另一个 $match 管道步骤完成的。

使用 $group 的最终聚合操作指定 null 的组 _id,使用累加器运算符计算管道中所有文档的总计数 $sum 在"unReadMessageCounts.count" 字段上。

所以,在给定的样本数据上运行这个聚合管道:

db.collection.aggregate([
    {
        "$match": { "unReadMessageCounts.participant": "user2" }
    },
    { "$unwind" : "$unReadMessageCounts" },
    {
        "$match": { "unReadMessageCounts.participant": "user2" }
    },    
    {
        "$group": {
            "_id": null,
            "total": { "$sum": "$unReadMessageCounts.count"  }
        }
    }
])

将产生结果:

/* 0 */
{
    "result" : [ 
        {
            "_id" : null,
            "total" : 3
        }
    ],
    "ok" : 1
}

【讨论】:

  • 虽然这解决了问题,但由于在第一个 $unwind 之后要处理的文档的大小,这不是解决问题的方法,而且您知道,如果您正在处理这可能是一个非常大的问题大量收藏。
【解决方案2】:

您可以使用$redact 运算符,如图所示here 来限制要在管道中处理的文档的大小,然后您$unwind 您的文档并在$group 阶段使用$sum 累加器运算符返回“user2”的未读消息总数。

db.collection.aggregate([
    { "$match": { 
        "unReadMessageCounts": { 
            "$elemMatch": { "participant": "user2" }
        }
    }},
    { "$redact": {
        "$cond": [
            { "$or": [
                { "$eq": [ "$participant", "user2" ] }, 
                { "$not" : "$participant" } 
            ]}, 
            "$$DESCEND", 
            "$$PRUNE" 
        ]
    }}, 
    { "$unwind": "$unReadMessageCounts" },
    { "$group": { 
        "_id": null, 
        "total": { "$sum": "$unReadMessageCounts.count" }
    }}
])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-10
    • 2016-04-11
    • 1970-01-01
    • 2015-03-15
    • 2017-12-10
    • 1970-01-01
    相关资源
    最近更新 更多