Du kan inte använda aggregation för att uppdatera ett dokument, men du kan definitivt använda det för att få de data du vill använda för en uppdatering. Först och främst märkte jag att det finns några {} saknas runt ditt grade objekt i grades array. Du kanske vill dubbelkolla att din dokumentstruktur är som den har lagts upp. För det andra finns det ett par problem med din aggregeringsfråga.
$avgoperatorn arbetar i en$groupsats, inte ett$project.- När du använder
$avg, du behöver inte använda$sum. - Du vill ha ett genomsnitt av
trucks.grades.grade.grade_number, som faktiskt håller betygets numeriska värde. Det vill säga, du saknargrademellangradeochgrade_number.
Om du löser dessa problem får du en fråga som liknar följande:
db.col.aggregate([
{ "$unwind": "$trucks" },
{ "$unwind": "$trucks.grades" },
{ "$group":
{
"_id": "$trucks.truck_id",
"average_grade": { "$avg": "$trucks.grades.grade_number" }
}
}
]);
För ditt exempeldokument returnerar det:
{ "_id" : "TEB5572", "average_grade" : 4 }
{ "_id" : "TEB7622", "average_grade" : 4 }
Nu kan du använda denna information för att uppdatera average_grade fält. Om du använder MongoDB version 2.6 eller högre, aggregate metod returnerar en markör. Du kan iterera genom den markören och uppdatera dokumenten därefter.
I det här exemplet söker jag efter dokument som har ett särskilt truck_id inuti sina trucks array och fortsätt med att uppdatera average_grade med den som beräknas av aggregeringsfrågan. Du kan modifiera den för att passa dina behov. I kombination med aggregeringsfrågan ser koden ut så här.
// Get average grade for each truck and assign results to cursor.
var cur = db.col.aggregate([
{ "$unwind": "$trucks" },
{ "$unwind": "$trucks.grades" },
{ "$group":
{
"_id": "$trucks.truck_id",
"average_grade": { "$avg": "$trucks.grades.grade_number" }
}
}
]);
// Iterate through results and update average grade for each truck.
while (cur.hasNext()) {
var doc = cur.next();
db.col.update({ "trucks.truck_id": doc._id },
{ "$set": { "trucks.$.average_grade": doc.average_grade }},
{ "multi": true});
}