首页 文章

使用Mongo聚合计算值的总和

提问于
浏览
1

我有发票,每张发票都包含一个项目列表 . 每个项目都包含以下字段(除其他外):

  • 名字

  • 数量

  • 总计

每张发票都有(除其他外)字段:

  • _id

  • 已创建

  • 项目

这些发票存放在专门的Mongo系列中,名为 invoices .

我想获取包含指定项目的所有发票,每张发票需要返回以下信息:

  • _id

  • 已创建

  • 数量(给定项目)

  • 总计(给定项目)

让我们将元组<id,date,qty,total>称为 invoice projection . 因此,结果应该是发票预测列表 .

如果发票两次列出给定项目,则相应的发票将生成两个投影实例 . 如果发票根本没有列出给定项目,则结果中不会显示此发票 .

无论如何,我正在使用以下Mongo聚合管道检索所需的投影:

pipeline = [
    {$match: {'items.name': req.params.name}},
    {$project: {created: 1, 'items.name': 1, 'items.qty': 1, 'items.total': 1}},
    {$unwind: '$items'},
    {$match: {'items.name': req.params.name}},
    {$project: {created: 1, qty: '$items.qty', total: '$items.total'}}
  ],

管道的工作方式如下:

  • 首先匹配具有给定名称的项目的所有发票 . items.name 上有一个Mongo索引,所以 $match 效率很高 .

  • 发票是一个大型对象,因此请删除所有字段,只留下以下结构: {_id: ?, created: ?, items: [{name: ?, qty: ?, total: ?}, ..., {name: ?, qty: ?, total: ?}]}

  • 展开 items 数组,现在我们有一个 {_id: ?, created: ?, 'items.name': ?, 'items.qty': ?, 'items.total': ?} 对象列表 .

  • 删除与给定名称不匹配的所有项目 .

  • 整理最终发票投影 .

然后,通过以下代码输入最终的发票预测列表:

function prepareResult(projections) {
  var res = projections.reduce(function (acc, item) {
    acc.itemCount += item.qty;
    acc.total += item.total;
    delete item.total;
    return acc;
  }, {itemCount: 0, total: 0});
  res.items = projections;
  return res;
}

它对所有发票预测中的 qtytotal 字段求和,并返回包含预测的新对象以及计算的总和 . 从每个发票投影中删除 total 字段,因为它只是所需的最终总和 .

我的问题 - 我可以将 prepareResult 函数的逻辑移到Mongo聚合管道中吗?

1 回答

  • 1

    您需要向管道添加$ group步骤 .

    组的_id将是你所总结的(在这种情况下是一个常数,因为你想要一个总数) . 由于您要保留发票清单,可以通过$ push运算符将它们累积到数组字段中 . 总金额和金额的总和将用$ sum处理 .

    {$group : { _id : 1,
                Total : { $sum : "$total" },
                ItemCount : { $sum : "$qty" },
                Invoices : { $push : { id : "$_id", created : "$created" }}
    } }
    

相关问题