Sum all values of same named fields of docs in a collection

怎甘沉沦 提交于 2020-08-09 07:19:22

问题


I have a database with the following documents:

{ 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  },

I want to calculate the total of hours spent in each of these fields. I accomplished that by:

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 }

Since at some point there will be dozens of fields in each document, is there any easier way to have the total fields be generated dynamically? (as in: check all fields in a document and if they exist in other docs in the collection, sum them all. If they don't exist in other docs, just display that field value as the total). For example, if I have:

{ 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  },

Should lead to:

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

Any suggestions? (without manually writing all the sums as in the aggregate example above)

Thanks!


回答1:


You can take advantage of $objectToArray and $arrayToObject operators to dynamically read your object keys. To get rid of _id and name fields you can $filter by $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



来源:https://stackoverflow.com/questions/58955059/sum-all-values-of-same-named-fields-of-docs-in-a-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!