在mongodb中的聚合中组合多个组

Mat*_*Kim 6 mongodb aggregation-framework

如果我有这样的集合:

{
    "store" : "XYZ",
    "total" : 100
},
{
    "store" : "XYZ",
    "total" : 200
},
{
    "store" : "ABC",
    "total" : 300
},
{
    "store" : "ABC",
    "total" : 400
}
Run Code Online (Sandbox Code Playgroud)

我可以$sum通过聚合获取集合中的订单:

db.invoices.aggregate([{$group: { _id: null, total: { $sum: "$total"}}}])

{
    "result": [{
            "_id": null,
            "total": 1000
        }
    ],
    "ok": 1
}
Run Code Online (Sandbox Code Playgroud)

我可以获得$sum按商店分组的订单:

db.invoices.aggregate([{$group: { _id: "$store", total: { $sum: "$total"}}}])

{
    "result": [{
            "_id": "ABC",
            "total": 700
        }, {
            "_id": "XYZ",
            "total": 300
        }
    ],
    "ok": 1
}
Run Code Online (Sandbox Code Playgroud)

但是如何在一个查询中执行此操作?

Bat*_*eam 13

您可以汇总如下:

  • $groupstore字段计算subtotal.

  • $project在下一组中,一个docsubtotal小组保持战略的领域.

  • $group通过null并累计净总额.

码:

db.invoices.aggregate([{
            $group: {
                "_id": "$store",
                "subtotal": {
                    $sum: "$total"
                }
            }
        }, {
            $project: {
                "doc": {
                    "_id": "$_id",
                    "total": "$subtotal"
                }
            }
        }, {
            $group: {
                "_id": null,
                "total": {
                    $sum: "$doc.total"
                },
                "result": {
                    $push: "$doc"
                }
            }
        }, {
            $project: {
                "result": 1,
                "_id": 0,
                "total": 1
            }
        }
    ])
Run Code Online (Sandbox Code Playgroud)

输出:

{
    "total": 1000,
    "result": [{
            "_id": "ABC",
            "total": 700
        }, {
            "_id": "XYZ",
            "total": 300
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

  • @MattKim - 谢谢.虽然聚合解决方案涉及多个阶段,但它比两个数据库调用高效工作,然后在应用程序代码中进行一些后期处理.如果解决方案涉及一些阶段,例如`$ unwind`,那将是不同的,这是非常昂贵的. (2认同)

ana*_*912 5

另一种方法是使用$facet聚合阶段。

  • $facet允许您 在主聚合中进行多个嵌套的聚合。
  • 每个子聚合都有自己的管道。
  • 对于子聚合的每个结果,我们定义另一个字段。

像这样,例如:

db.invoices.aggregate([
    {
        $facet: {
            total: [
                {
                    $group: {
                        _id: null,
                        total: { $sum: "$total"}
                    }
                }
            ],
            store_totals: [
                {
                    $group: {
                        _id: "$store",
                        total: { $sum: "$total"}
                    }
                }
            ]
        }
    },{
        $unwind: "$total"
    },{
        $project: {
            _id: 0,
            total: "$total.total",
            store_totals: "$store_totals"
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

@BatScream 写道,一个$unwind阶段可能会很昂贵。然而,我们在这里展开一个长度为 1 的数组。所以我很好奇哪种方法在哪种情况下更有效。如果有人可以将这些与 进行比较console.time(),我很乐意将结果包括在内。


输出

应该与接受的答案相同。