Mongodb: 聚合:对 $group 之前的数组中的值求和

Mongodb: Aggregation : sum up values in an array before $group

我有一组具有以下结构的文档:

{
    _id: 1,
    array: [
        {value: 10 },
        {value: 11 },
        {value: 12 }
    ]
}

我想对集合进行聚合查询: 得到每个项目的比例。 (例如,项目 1 的比例将是项目 1 的 value 除以所有三个项目的值之和。

注意:我想在单个查询中执行此操作。

这里的基本思想是$unwind the array, $group the document and then apply to each array member. This works better for MongoDB 2.6 or greater due to the $map运算符:

db.collection.aggregate([
    { "$unwind": "$array" },
    { "$group": {
       "_id": "$_id",
       "array": { "$push": "$array" },
       "total": { "$sum": "$array.value" }
    }},
    { "$project": {
        "array": {
            "$map": {
                "input": "$array",
                "as": "el",
                "in": {
                    "value": "$$el.value",
                    "prop": { 
                        "$divide": [ "$$el.value", "$total" ]
                    }
                }
            }
        }
    }}
])

或早期版本:

db.collection.aggregate([
    { "$unwind": "$array" },
    { "$group": {
       "_id": "$_id",
       "array": { "$push": "$array" },
       "total": { "$sum": "$array.value" }
    }},
    { "$unwind": "$array" },
    { "$group": {
        "_id": "$_id",
        "array": {
            "$push": {
                "value": "$array.value",
                "prop": {
                    "$divide": [ "$array.value", "$total" ]
                }
            }
        }
    }}
])

在任何一种情况下,如果您实际上 "aggregating" 文档之外的任何内容,在客户端代码中执行此计算的效率要高得多。 $unwind 由于其作用,此处的 $unwind 可能会变得非常昂贵。

此外,如果您只是将 "total" 存储为另一个元素,那么简单的 $project 就是您所需要的,而且成本非常低通过它自己。保持总计更新只是对数组 $inc operator as you $push 新元素的简单使用。

这是您需要的聚合管道:

[
    {$unwind: '$array'},
    {
        $group: {
            _id: '$_id', 
            array: {$push: '$array'}, 
            sum: {$sum: '$array.value'}
        }
    }, 
    {$unwind: '$array'},
    {
        $project: {
            _id: 1,
           'array.value': 1, 
           'array.proportion': {
               $divide: ['$array.value', '$sum']
           }
        }
    }
]