Mongodb:Aggregation:在$ group之前对数组中的值求和

Mer*_*aye 1 mongodb mongodb-query aggregation-framework

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

{
    _id: 1,
    array: [
        {value: 10 },
        {value: 11 },
        {value: 12 }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我想在集合上进行聚合查询: 获取每个项目的比例.(即,例如项目1的比例将是value项目1除以所有三个项目的值的总和.

注意:我想在一个查询中执行此操作.

Bla*_*ven 5

这里的基本思想是$unwind将数组,$group文档然后应用于每个数组成员.由于$map运营商的原因,这对MongoDB 2.6或更高版本更有效:

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" ]
                    }
                }
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

或者使用早期版本:

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" ]
                }
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,如果您实际上并没有"聚合"文档之外的任何内容,那么在客户端代码中进行此计算会更有效.$unwind由于它的作用,这里可能会变得非常昂贵.

此外,如果您只是将"total"存储为另一个元素,那么简单$project就是您需要的所有内容,而且本身成本非常低.保持更新总数只是简单地使用$inc运算符作为$push数组的新元素.