MongoDb - 聚合:如何获得具有个人,未分组记录的总计?

时间:2018-01-07 17:24:58

标签: mongodb

我们说我们有以下文件:

{ type: "hourly", amount: 100 },
{ type: "flat", amount: 350 },
{ type: "hourly", amount: 200 },
{ type: "payment", amount: 100 },
{ type: "payment", amount: 200 }

在管道中的某个地方,我想为每个"类型积累总计。" 除了所有个人记录之外,我想知道我们的总计如下:

hourly:  $300
flat:    $350
payment: $300

我查看了 $ add $ sum ,这些似乎对添加给定记录的字段非常有用,而不是累积总计。

到目前为止,我的聚合过滤了我想要的所有记录,并且不使用任何分组。我不想将记录分组。我需要个人记录以及总计。

我认为 $ push 命令可能是相关的,如果我必须 $ group - 可能是 $ push - 将个人记录转换为一个数组,使其与所有其余记录一起退出。请在此处查看答案:Using Mongo aggregation to calculate sum of values

在我的情况下,我有一个聚合,没有收集任何总数,如下所示。对于每个返回的文档,都有一个"类型"字段(例如,"每小时","平,""付款")。

myAggregate = [
    { $sort: { date: -1 } },
    {
        $match: query
    },
    {
        $lookup: {
            from: "contacts", // collection name in db
            localField: "billerId",
            foreignField: "_id",
            as: "biller"
        }
    },
    {
        $unwind: "$biller"
    },
    {
        $lookup: {
            from: "matters", // collection name in db
            localField: "matterId",
            foreignField: "_id",
            as: "matter"
        }
    },
    {
        $unwind: "$matter"
    },
    {
        $lookup: {
            from: "contacts", // collection name in db
            localField: "matter.clientId",
            foreignField: "_id",
            as: "client"
        }
    },
    {
        $unwind: "$client"
    },
];

" myAggregate"看起来是为了积累总计并返回所有个人(未分组)记录?

经过深思熟虑:如果对我来说同样有效的话,那就是"手动"遍历记录以获得总计,我可以做到这一点。我认为MongoDb必须更有效率,因为他们不愿意制作这些功能。

编辑1:

以下是" myAggregate"根据Veeram的建议附加:

// Do we need to get only records which match the matter's contactId?
if (query2 != "") {
    myAggregate.push( { $match: query2 } );
}

// Get grand totals.
myAggregate.push({ "$group": { "_id": "$transactionType",
                "documents": { "$push": "$$ROOT" },
                "grandtotal": {"$sum":"$amount"}
           }
});

1 个答案:

答案 0 :(得分:1)

在Veeram的帮助下,我通过在他建议的project阶段之前添加group阶段来获得总数。我还将group的_id设置为 null (根据Mongo documentation),以避免将我的所有文档分成组。

    $project: {
        _id: 1,
        firmId: 1,

        ... plus, a bunch more fields.

        // Project some fields to allow totaling by transactionType.
        hourlyAmount: { $cond: { if: { $eq: ["$transactionType", "hourly"] }, then: "$amount", else: 0 } },
        flatAmount: { $cond: { if: { $eq: ["$transactionType", "flat"] }, then: "$amount", else: 0 } },
        paymentAmount: { $cond: { if: { $eq: ["$transactionType", "payment"] }, then: "$amount", else: 0 } },
        expenseAmount: { $cond: { if: { $eq: ["$transactionType", "expense"] }, then: "$amount", else: 0 } },
        creditAmount: { $cond: { if: { $eq: ["$transactionType", "credit"] }, then: "$amount", else: 0 } },
        debitAmount: { $cond: { if: { $eq: ["$transactionType", "debit"] }, then: "$amount", else: 0 } }

    }

然后,根据Veeram,我分组如下:

myAggregate.push({
    "$group": {
        "_id": null, //"$transactionType",
        "documents": { "$push": "$$ROOT" },
        "hourlyTotal": {"$sum": "$hourlyAmount"},
        "flatTotal" :  {"$sum": "$flatAmount"},
        "paymentTotal" :  {"$sum": "$paymentAmount"},
        "expenseTotal" :  {"$sum": "$expenseAmount"},
        "creditTotal" :  {"$sum": "$creditAmount"},
        "debitTotal" :  {"$sum": "$debitAmount"},
    }
});

它工作得很漂亮,一切都以一个元素的形式返回。请注意,“documents”是数组元素的属性,因此它们可以由<arrayElements>[0]。文档引用。我的所有个人总数都在那里(例如,arrayElements>[0].hourlyTotal)。