MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDB :Mise à jour d'une moyenne dans un document avec 2 tableaux imbriqués

Vous ne pouvez pas utiliser l'aggregation pour mettre à jour un document, mais vous pouvez certainement l'utiliser pour obtenir les données que vous souhaitez utiliser pour une mise à jour. Tout d'abord, j'ai remarqué qu'il y a des {} manquant autour de votre grade objet à l'intérieur des grades déployer. Vous voudrez peut-être vérifier que la structure de votre document est telle que publiée. Deuxièmement, il y a quelques problèmes avec votre requête d'agrégation.

  1. Le $avg l'opérateur travaille à l'intérieur d'un $group clause, pas un $project .
  2. Lorsque vous utilisez $avg , vous n'avez pas besoin d'utiliser $sum .
  3. Vous voulez faire la moyenne de trucks.grades.grade.grade_number , qui contient en fait la valeur numérique de la note. C'est-à-dire qu'il vous manque grade entre grades et grade_number .

Si vous résolvez ces problèmes, vous obtenez une requête semblable à la suivante :

db.col.aggregate([ 
    { "$unwind": "$trucks" }, 
    { "$unwind": "$trucks.grades" }, 
    { "$group":
        { 
            "_id": "$trucks.truck_id", 
            "average_grade": { "$avg": "$trucks.grades.grade_number" } 
        } 
    }
]);

Pour votre exemple de document, cela renvoie :

{ "_id" : "TEB5572", "average_grade" : 4 }
{ "_id" : "TEB7622", "average_grade" : 4 }

Vous pouvez maintenant utiliser ces informations pour mettre à jour le average_grade champ. Si vous utilisez MongoDB version 2.6 ou supérieure, le aggregate méthode renverra un curseur. Vous pouvez parcourir ce curseur et mettre à jour les documents en conséquence.

Dans cet exemple, je recherche des documents qui ont un truck_id particulier à l'intérieur de leurs trucks tableau et procéder à la mise à jour du average_grade avec celui calculé par la requête d'agrégation. Vous pouvez le modifier selon vos besoins. Combiné avec la requête d'agrégation, le code ressemble à ceci.

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