MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Suma poddokumentów w Mongoose

Korzystanie z aggregate() funkcji, możesz uruchomić następujący potok, który używa $sum operatora, aby uzyskać pożądane wyniki:

const results = await Cart.aggregate([
    { "$addFields": {
        "totalPrice": {
            "$sum": "$products.subTotal"
        }
    } },
]);

console.log(JSON.stringify(results, null, 4));

a odpowiednia operacja aktualizacji następuje:

db.carts.updateMany(
   { },
   [
        { "$set": {
            "totalPrice": {
                "$sum": "$products.subTotal"
            }
        } },
    ]
)

Lub jeśli używasz MongoDB 3.2 i wcześniejszych wersji, gdzie $sum jest dostępny tylko w fazie $group, możesz to zrobić

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));
    })

W powyższym potoku pierwszym krokiem jest $odpręż operator

{ "$unwind": "$products" }

co jest bardzo przydatne, gdy dane są przechowywane w postaci tablicy. Gdy operator unwind zostanie zastosowany do pola danych listy, wygeneruje nowy rekord dla każdego elementu pola danych listy, do którego zastosowano unwind. Zasadniczo spłaszcza dane.

Jest to niezbędna operacja na następnym etapie potoku, $grupa krok, w którym grupujesz spłaszczone dokumenty według _id pole, w ten sposób skutecznie przegrupowując zdenormalizowane dokumenty z powrotem do ich oryginalnego schematu.

$group Operator potoku jest podobny do GROUP BY w SQL klauzula. W SQL nie możesz używać GROUP BY chyba że korzystasz z którejkolwiek z funkcji agregacji. W ten sam sposób musisz również użyć funkcji agregacji w MongoDB (zwanej akumulatorami). Więcej informacji o akumulatorach znajdziesz tutaj .

W tym $group operacja, logika obliczania całkowitej ceny a zwrócenie oryginalnych pól odbywa się za pomocą akumulatorów . Otrzymujeszcałkowitą cenę sumując każdą pojedynczą subTotal wartości na grupę z $sum jako:

"totalPrice": { "$sum": "$products.subTotal }

Drugie wyrażenie

"userPurchased": { "$first": "$userPurchased" },

zwróci zakupiony przez użytkownika wartość z pierwszego dokumentu dla każdej grupy przy użyciu $first . W ten sposób skutecznie odbudowuje oryginalny schemat dokumentu przed $odpręż

Należy zauważyć, że podczas wykonywania potoku MongoDB łączy ze sobą operatorów. "Pipe" ma tutaj znaczenie Linuksa:wyjście operatora staje się wejściem następującego operatora. Rezultatem każdego operatora jest nowy zbiór dokumentów. Tak więc Mongo wykonuje powyższy potok w następujący sposób:

collection | $unwind | $group => result

Na marginesie, aby pomóc w zrozumieniu potoku lub debugowaniu go w przypadku uzyskania nieoczekiwanych wyników, uruchom agregację tylko z pierwszym operatorem potoku. Na przykład uruchom agregację w powłoce mongo jako:

db.cart.aggregate([
    { "$unwind": "$products" }
])

Sprawdź wynik, aby zobaczyć, czy produkty tablica jest poprawnie dekonstruowana. Jeśli daje to oczekiwany wynik, dodaj następny:

db.cart.aggregate([
    { "$unwind": "$products" },
    {
        "$group": {
            "_id": "$_id",
            "products": { "$push": "$products" },
            "userPurchased": { "$first": "$userPurchased" },
            "totalPrice": { "$sum": "$products.subTotal" }
        }
    }
])

Powtarzaj kroki, aż dojdziesz do ostatniego etapu potoku.

Jeśli chcesz zaktualizować pole, możesz dodać $out etap rurociągu jako ostatni krok. Spowoduje to zapisanie wynikowych dokumentów potoku agregacji do tej samej kolekcji, a tym samym techniczną aktualizację kolekcji.

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
]

AKTUALIZUJ

Aby wykonać zarówno aktualizację, jak i zapytanie, możesz następnie wydać find() zadzwoń w zagregowanym wywołaniu zwrotnym, aby uzyskać zaktualizowany 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));
        })
    })
    

Korzystając z Promises, możesz to zrobić alternatywnie jako

Cart.aggregate(pipeline).exec().then(function(res)
    return Cart.find().exec();
).then(function(docs){  
    console.log(JSON.stringify(docs, null, 4));
});


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongo i Node.js:znajdowanie dokumentu według _id przy użyciu identyfikatora UUID (GUID)

  2. Nodejs nie może połączyć się z mongodb w chmurze powłoki

  3. wstaw tablicę do mongodb za pomocą pymongo

  4. Jak zaktualizować wszystkie dokumenty w mongodb PHP?

  5. Nie można nadpisać modelu `users` po skompilowanym węźle js