MongoDB:使用2个嵌套数组更新文档中的平均值

sue*_*mol 6 arrays mongodb mongodb-query

我有以下MongoDB文档:

{
    _id: ObjectId(),
    company_name: "Name",
    registered: 2/21/2015 2:00,
    trucks: [
        {
            truck_id: "TEB7622",
            weight: 88.33,
            capacity: 273.333,
            length: 378.333,
            width: 377.383,
            average_grade: 2.5,
            grades: [
                {
                    grade_number: 4,
                    timestamp: 2/21/2015 2:00
                }
            ]
        },
        {
            truck_id: "TEB5572",
            weight: 854.33,
            capacity: 2735.333,
            length: 378.333,
            width: 37.383,
            average_grade: 3.8,
            grades: [
                {
                    grade_number: 4,
                    timestamp: 2/21/2015 2:00
                }
            ]
        }
    ]

}
Run Code Online (Sandbox Code Playgroud)

我想average_grade通过添加所有的更新每辆卡车grade_numbers.我遇到的问题是grade_numbers我试图添加的是数组中的数组.我试过$unwind用来放松卡车和等级阵列.

这是我尝试过的查询:

db.col.aggregate([ 
   {$unwind: "$trucks"}, 
   {$unwind: "$trucks.grades"}, 
   { $project: { 
      "_id": "$trucks.truck_id", 
      "trucks.average_grade": { $avg: { $sum: "trucks.grades.grade_number"} } 
      } 
   }])
Run Code Online (Sandbox Code Playgroud)

我是否必须在查询中添加更多内容?我想更新所有的trucks.average_grades,因为在我试图更新的文档中有很多这些.

Jua*_*rah 6

您无法使用aggregation更新文档,但您绝对可以使用它来获取要用于更新的数据.首先,我注意到数组中{}grade对象周围有一些缺失grades.您可能需要仔细检查文档结构是否已发布.其次,您的聚合查询存在一些问题.

  1. $avg运营商工作的内部$group条款,而不是一个$project.
  2. 使用时$avg,您不需要使用$sum.
  3. 你想要平均trucks.grades.grade.grade_number,实际上保持等级的数值.也就是说,你和grade之间缺少.gradesgrade_number

如果您解决了这些问题,则会得到类似于以下内容的查询:

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

对于您的示例文档,它返回:

{ "_id" : "TEB5572", "average_grade" : 4 }
{ "_id" : "TEB7622", "average_grade" : 4 }
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用此信息更新该average_grade字段.如果您使用的是MongoDB 2.6或更高版本,该aggregate方法将返回一个游标.您可以遍历该游标并相应地更新文档.

在此示例中,我搜索truck_id在其trucks数组中具有特定内容的文档,并继续average_grade使用聚合查询计算的文档进行更新.您可以根据自己的需要进行修改.结合聚合查询,代码如下所示.

// 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});
}
Run Code Online (Sandbox Code Playgroud)