对集合中文档的相同命名字段的所有值求和

时间:2019-11-20 13:05:34

标签: mongodb aggregation-framework

我有一个包含以下文档的数据库:

{ name: "John", a: 20, b: 30, c: 40, d: 50  },     
{ name: "Rich", a: 20, b: 30, c: 40, d: 50  },      
{ name: "Anne", a: 20, b: 30, c: 40, d: 50  },      
{ name: "Sam", a: 20, b: 30, c: 40, d: 50  },

我想计算在每个字段中花费的总时间。我是通过以下方式实现的:

db.hours.aggregate([{$group: {_id: null, totalA: {$sum: "$a"}, totalB: {$sum: "$b"}, totalC: {$sum: "$c"}, totalD: {$sum: "$d"}}}])
{ "_id" : null, "totalA" : 80, "totalB" : 120, "totalC" : 160, "totalD" : 200 }

由于某些时候每个文档中都会有几十个字段,所以有没有更简单的方法可以动态生成总字段? (例如:检查文档中的所有字段,如果它们在集合中的其他文档中存在,则将它们全部加起来。如果在其他文档中不存在,则将该字段值显示为总计)。例如,如果我有:

{ name: "John", a: 20, b: 30, e: 40, f: 50  },     
{ name: "Rich", a: 20, b: 30, c: 40, d: 50  },      
{ name: "Anne", a: 20, b: 30, g: 40, h: 50  },      
{ name: "Sam", a: 20, b: 30, c: 40, d: 50  },

应导致:

{"a" : 80, "b" : 120, "c" : 80, "d" : 100, "e" : 40, "f" : 50, "g" : 40, "h": 50 }

有什么建议吗? (无需像上面的汇总示例一样手动写入所有总和)

谢谢!

1 个答案:

答案 0 :(得分:1)

您可以利用$objectToArray$arrayToObject运算符来动态读取对象键。要摆脱_idname字段,您可以$filter $type来代替。

db.collection.aggregate([
    {
        $project: {
            _id: 0,
            fields: {
                $filter: {
                    input: { $objectToArray: "$$ROOT" },
                    cond: { $eq: [ { $type: "$$this.v" }, "double" ] }
                }
            }
        }
    },
    {
        $unwind: "$fields"
    },
    {
        $group: {
            _id: "$fields.k",
            total: { $sum: "$fields.v" }
        }
    },
    {
        $group: {
            _id: null,
            aggregates: { $push: { k: "$_id", v: "$total" } }
        }
    },
    {
        $replaceRoot: {
            newRoot: { $arrayToObject: "$aggregates" }
        }
    }
])

Mongo Playground