【问题标题】:condtitional aggregate function in mongodbMongoDB中的条件聚合函数
【发布时间】:2017-02-19 16:36:34
【问题描述】:

我有一个数据为

的 mongodb
{
  "_id": "a",
  "reply": "<",
  "criterion": "story"
},
{
  "_id": "b",
  "reply": "<",
  "criterion": "story"
},
{
  "_id": "c",
  "reply": ">",
  "criterion": "story"
}

我希望结果为:

 {
   "criterion": "story",
   "result" : {
                ">" : 1,
                "<" : 2
              } 
 }

我想汇总“标准”。因此,如果我这样做,将有 1 个文档。但是,我想计算“”的数量并将其写入新键中,如上面的 json 所示。这就是这背后的逻辑。任何对 mongodb 有好主意的人都可以帮我解决这个问题吗?

【问题讨论】:

    标签: javascript mongodb mongoose aggregation-framework mongodb-aggregation


    【解决方案1】:

    您需要使用聚合框架,在其中运行聚合管道,该管道具有 $group 运算符管道阶段,该阶段聚合文档以使用累加器运算符创建所需的计数 $sum

    为了获得所需的结果,您需要使用像 $cond 这样的三元运算符来创建独立的计数字段,因为这会将文档数提供给 $sum 表达式取决于名称值。 $cond 运算符可以有效地用于根据reply 字段值评估计数。它将逻辑条件作为其第一个参数 (if),然后返回计算结果为 true (then) 的第二个参数或返回 false (else) 的第三个参数。这会将 true/false 布尔计算的返回值转换为 1 和 0,它们将分别输入 $sum

    "$cond": [
        { "$eq": ["$reply", ">"] },
        1, 0
    ]
    

    因此,如果在正在处理的文档中 "$reply" 字段具有 "&gt;" 值,则 $cond 运算符会将值 1 提供给 $sum 否则它的总和为零。

    使用 $project 作为您的最后一个管道步骤,因为它允许您重塑流中的每个文档,包括、排除或重命名字段,注入计算字段,创建子文档字段,使用数学表达式、日期、字符串和/或逻辑(比较、布尔、控制)表达式。它类似于 SQL 中的SELECT

    以下管道应返回所需的结果:

    Model.aggregate([
        {
            "$group": {
                "_id": "$criterion",
                ">": {
                    "$sum": {
                        "$cond": [ 
                            { "$eq": [ "$reply", ">" ] }, 
                            1, 0 
                        ]
                    }
                },
                "<": {
                    "$sum": {
                        "$cond": [ 
                            { "$eq": [ "$reply", "<" ] }, 
                            1, 0 
                        ]
                    }
                }
            }
        },
        {
            "$project": {
                "_id": 0,
                "criterion": "$_id",
                "result.>": "$>",
                "result.<": "$<"
            }
        }
    ]).exec(function(err, result) {
        console.log(JSON.stringify(result, null, 4));
    });
    

    控制台输出示例

    {
        "criterion" : "story",
        "result" : {
            ">" : 1,
            "<" : 2
        }
    }
    

    注意:这种方法考虑到$reply 字段的值是固定且已知的,因此在值是动态且未知的情况下它不灵活。


    对于一个比上述执行速度更快、性能更好并且还考虑到计数字段的未知值的更灵活的替代方案,我建议按如下方式运行管道:

    Model.aggregate([
        { 
            "$group": {
                "_id": {
                    "criterion": "$criterion",
                    "reply": "$reply"
                },
                "count": { "$sum": 1 }
            }
        },
        { 
            "$group": {
                "_id": "$_id.criterion",
                "result": {
                    "$push": {
                        "reply": "$_id.reply",
                        "count": "$count"
                    }
                }
            }
        }
    ]).exec(function(err, result) {
        console.log(JSON.stringify(result, null, 4));
    });
    

    控制台输出示例

    {
        "_id" : "story",
        "result" : [ 
            {
                "reply" : "<",
                "count" : 2
            }, 
            {
                "reply" : ">",
                "count" : 1
            }
        ]
    }
    

    【讨论】:

    • 非常出色的工作非常感谢@chridam 这真的很有帮助。你马上就明白我的问题了。
    • @neaGaze 不用担心,总是乐于提供帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 2014-06-08
    • 2021-02-22
    • 2012-11-30
    • 2017-11-25
    • 1970-01-01
    • 2019-03-05
    相关资源
    最近更新 更多