請求書があり、各請求書にはアイテムのリストが含まれています。各項目には (特に) 次のフィールドがあります。
- 名前
- 数量
- 合計
また、各請求書には (特に) 次のフィールドがあります。
- _id
- 作成した
- アイテム
請求書は、請求書と呼ばれる専用の Mongo コレクションにあります。
指定されたアイテムを含むすべての請求書を取得したいと考えています。各請求書について、次の情報を返す必要があります。
- _id
- 作成した
- 数量(指定されたアイテムの)
- 合計(指定されたアイテムの)
タプル <id, date, qty, total> を請求書のプロジェクションと呼びましょう。したがって、結果は請求書予測のリストになるはずです。
請求書に特定の項目が 2 回記載されている場合、それぞれの請求書は 2 つのプロジェクション インスタンスを生成します。請求書に特定の項目がまったく記載されていない場合、この請求書は結果に表示されません。
とにかく、次の 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'}}
],
パイプラインは次のように機能します。
- 最初に、指定された名前のアイテムを持つすべての請求書を照合します。には Mongo インデックスが
items.name
あるので、これ$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 集計パイプラインに移動できますか?