Pomocí aggregate()
můžete spustit následující kanál, který používá $sum
operátor k získání požadovaných výsledků:
const results = await Cart.aggregate([
{ "$addFields": {
"totalPrice": {
"$sum": "$products.subTotal"
}
} },
]);
console.log(JSON.stringify(results, null, 4));
a následuje odpovídající operace aktualizace:
db.carts.updateMany(
{ },
[
{ "$set": {
"totalPrice": {
"$sum": "$products.subTotal"
}
} },
]
)
Nebo pokud používáte MongoDB 3.2 a starší verze, kde $sum
je k dispozici pouze ve fázi $group, můžete to udělat
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));
})
Ve výše uvedeném kanálu je prvním krokem $unwind
operátor
{ "$unwind": "$products" }
což je docela užitečné, když jsou data uložena jako pole. Když je operátor odvíjení aplikován na datové pole seznamu, vygeneruje nový záznam pro každý prvek datového pole seznamu, na který je aplikováno odvíjení. V podstatě zplošťuje data.
Toto je nezbytná operace pro další fázi kanálu, $group
krok, ve kterém seskupujete sloučené dokumenty podle _id
pole, čímž efektivně přeskupíte denormalizované dokumenty zpět do jejich původního schématu.
$group
Operátor potrubí je podobný SQL GROUP BY
doložka. V SQL nemůžete použít GROUP BY
pokud nepoužíváte některou z agregačních funkcí. Stejně tak musíte v MongoDB použít agregační funkci (nazývanou akumulátory). Další informace o akumulátorech si můžete přečíst zde
.
V této $skupině
operace, logika pro výpočet totalPrice
a vrácení původních polí je prostřednictvím akumulátorů . Získáte totalPrice
sečtením každého jednotlivého mezisoučtu
hodnoty na skupinu s $sum
jako:
"totalPrice": { "$sum": "$products.subTotal }
Druhý výraz
"userPurchased": { "$first": "$userPurchased" },
vrátí userPurchased
hodnotu z prvního dokumentu pro každou skupinu pomocí $first
. Efektivně tak znovu sestaví původní schéma dokumentu před $unwind
Jedna věc, kterou je třeba poznamenat, je, že při provádění kanálu MongoDB spojuje operátory navzájem. "Pipe" zde má význam Linux:výstup operátora se stává vstupem následujícího operátora. Výsledkem každého operátora je nová sbírka listin. Mongo tedy provede výše uvedený kanál následovně:
collection | $unwind | $group => result
Jako vedlejší poznámku, chcete-li pomoci s pochopením kanálu nebo jej ladit, pokud byste získali neočekávané výsledky, spusťte agregaci pouze s prvním operátorem kanálu. Například spusťte agregaci v mongo shell jako:
db.cart.aggregate([
{ "$unwind": "$products" }
])
Zkontrolujte výsledek, zda produkty
pole je správně dekonstruováno. Pokud to dává očekávaný výsledek, přidejte následující:
db.cart.aggregate([
{ "$unwind": "$products" },
{
"$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"userPurchased": { "$first": "$userPurchased" },
"totalPrice": { "$sum": "$products.subTotal" }
}
}
])
Opakujte kroky, dokud se nedostanete ke konečnému kroku potrubí.
Pokud chcete pole aktualizovat, můžete přidat $out
fáze potrubí jako poslední krok. Tím se výsledné dokumenty agregačního kanálu zapíší do stejné kolekce, čímž se kolekce technicky aktualizuje.
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
]
AKTUALIZACE
Chcete-li provést aktualizaci i dotaz, můžete zadat find()
zavolejte agregované zpětné volání, abyste získali aktualizovaný soubor json, tj.
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));
})
})
Pomocí Promises to můžete udělat alternativně jako
Cart.aggregate(pipeline).exec().then(function(res)
return Cart.find().exec();
).then(function(docs){
console.log(JSON.stringify(docs, null, 4));
});