我有一个包含以下文档的数据库:
{ 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 }
有什么建议吗? (无需像上面的汇总示例一样手动写入所有总和)
谢谢!
答案 0 :(得分:1)
您可以利用$objectToArray和$arrayToObject运算符来动态读取对象键。要摆脱_id
和name
字段,您可以$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" }
}
}
])