我有发票,每张发票都包含一个项目列表 . 每个项目都包含以下字段(除其他外):
-
名字
-
数量
-
总计
每张发票都有(除其他外)字段:
-
_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;
}
它对所有发票预测中的 qty
和 total
字段求和,并返回包含预测的新对象以及计算的总和 . 从每个发票投影中删除 total
字段,因为它只是所需的最终总和 .
我的问题 - 我可以将 prepareResult
函数的逻辑移到Mongo聚合管道中吗?
1 回答
您需要向管道添加$ group步骤 .
组的_id将是你所总结的(在这种情况下是一个常数,因为你想要一个总数) . 由于您要保留发票清单,可以通过$ push运算符将它们累积到数组字段中 . 总金额和金额的总和将用$ sum处理 .