MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDB:Atualizando uma média em um documento com 2 arrays aninhados


Você não pode usar aggregation para atualizar um documento, mas você pode definitivamente usá-lo para obter os dados que deseja usar para uma atualização. Em primeiro lugar, notei que existem alguns {} faltando na sua grade objeto dentro das grades variedade. Você pode querer verificar novamente se a estrutura do seu documento está conforme lançada. Em segundo lugar, há alguns problemas com sua consulta de agregação.
  1. O $avg operador trabalha dentro de um $group cláusula, não um $project .
  2. Quando você usa $avg , você não precisa usar $sum .
  3. Você deseja calcular a média de trucks.grades.grade.grade_number , que na verdade contém o valor numérico da nota. Ou seja, está faltando grade entre grades e grade_number .

Se você resolver esses problemas, receberá uma consulta semelhante à seguinte:
db.col.aggregate([ 
    { "$unwind": "$trucks" }, 
    { "$unwind": "$trucks.grades" }, 
    { "$group":
        { 
            "_id": "$trucks.truck_id", 
            "average_grade": { "$avg": "$trucks.grades.grade_number" } 
        } 
    }
]);

Para seu documento de amostra, isso retorna:
{ "_id" : "TEB5572", "average_grade" : 4 }
{ "_id" : "TEB7622", "average_grade" : 4 }

Agora você pode usar essas informações para atualizar o average_grade campo. Se você estiver usando o MongoDB versão 2.6 ou superior, o aggregate O método retornará um cursor. Você pode percorrer esse cursor e atualizar os documentos de acordo.

Neste exemplo, procuro documentos que tenham um determinado truck_id dentro de seus trucks array e prossiga para atualizar o average_grade com o calculado pela consulta de agregação. Você pode modificá-lo para atender às suas necessidades. Combinado com a consulta de agregação, o código se parece com isso.
// 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});
}