Aggregate()
を使用する
関数を使用すると、 $sumを使用する次のパイプラインを実行できます。
目的の結果を得るための演算子:
const results = await Cart.aggregate([
{ "$addFields": {
"totalPrice": {
"$sum": "$products.subTotal"
}
} },
]);
console.log(JSON.stringify(results, null, 4));
対応する更新操作は次のとおりです。
db.carts.updateMany(
{ },
[
{ "$set": {
"totalPrice": {
"$sum": "$products.subTotal"
}
} },
]
)
または、MongoDB 3.2以前のバージョンを使用している場合、 $ sum
$groupステージでのみ利用可能です。実行できます
const pipeline = [
{ "$unwind": "$products" },
{
"$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"userPurchased": { "$first": "$userPurchased" },
"totalPrice": { "$sum": "$products.subTotal" }
}
}
]
Cart.aggregate(pipeline)
.exec(function(err, results){
if (err) throw err;
console.log(JSON.stringify(results, null, 4));
})
上記のパイプラインでは、最初のステップは $ unwind
オペレーター
{ "$unwind": "$products" }
これは、データが配列として格納されている場合に非常に便利です。アンワインド演算子がリストデータフィールドに適用されると、アンワインドが適用されるリストデータフィールドのすべての要素に対して新しいレコードが生成されます。基本的にデータをフラット化します。
これは、次のパイプラインステージである $ group
平坦化されたドキュメントを_id
でグループ化するステップ フィールド、したがって、非正規化されたドキュメントを元のスキーマに効果的に再グループ化します。
$ group
>
パイプライン演算子は、SQLの GROUP BY
に似ています 句。 SQLでは、 GROUP BY
は使用できません。 集計関数のいずれかを使用しない限り。同様に、MongoDBの集計関数(アキュムレーターと呼ばれる)も使用する必要があります。 アキュムレータについて詳しくは、こちらをご覧ください
。
この $ group コード>
totalPrice
を計算するロジック 元のフィールドを返すには、アキュムレータ> 。 totalPrice
を取得します 個々のsubTotal
を合計する $ sum
を使用したグループごとの値 として:
"totalPrice": { "$sum": "$products.subTotal }
他の表現
"userPurchased": { "$first": "$userPurchased" },
userPurchased
を返します $ first
を使用した各グループの最初のドキュメントの値 。したがって、 の前に、元のドキュメントスキーマを効果的に再構築します。 $ unwind
ここで注意すべきことの1つは、パイプラインを実行するときに、MongoDBがオペレーターを相互にパイプすることです。ここでの「パイプ」はLinuxの意味を取ります。演算子の出力は、次の演算子の入力になります。各演算子の結果は、ドキュメントの新しいコレクションです。したがって、Mongoは上記のパイプラインを次のように実行します。
collection | $unwind | $group => result
補足として、パイプラインの理解を支援したり、予期しない結果が発生した場合にデバッグしたりするには、最初のパイプライン演算子だけで集計を実行します。たとえば、mongoシェルで次のように集計を実行します:
db.cart.aggregate([
{ "$unwind": "$products" }
])
結果をチェックして、 products
かどうかを確認します 配列は適切に分解されます。それで期待どおりの結果が得られた場合は、次を追加します:
db.cart.aggregate([
{ "$unwind": "$products" },
{
"$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"userPurchased": { "$first": "$userPurchased" },
"totalPrice": { "$sum": "$products.subTotal" }
}
}
])
パイプラインの最後のステップに到達するまで、ステップを繰り返します。
フィールドを更新する場合は、 $ out
最後のステップとしてのパイプラインステージ。これにより、集計パイプラインの結果のドキュメントが同じコレクションに書き込まれるため、コレクションが技術的に更新されます。
var pipeline = [
{ "$unwind": "$products" },
{
"$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"userPurchased": { "$first": "$userPurchased" },
"totalPrice": { "$sum": "$products.subTotal" }
}
},
{ "$out": "cart" } // write the results to the same underlying mongo collection
]
更新
更新とクエリの両方を行うには、 find()
を発行します。 集約コールバックを呼び出して、更新されたjsonを取得します。
Cart.aggregate(pipeline)
.exec(function(err, results){
if (err) throw err;
Cart.find().exec(function(err, docs){
if (err) return handleError(err);
console.log(JSON.stringify(docs, null, 4));
})
})
Promisesを使用すると、代わりにこれを行うことができます
Cart.aggregate(pipeline).exec().then(function(res)
return Cart.find().exec();
).then(function(docs){
console.log(JSON.stringify(docs, null, 4));
});