MongoDB:使用 2 个嵌套数组更新文档中的平均值
MongoDB: Updating an average in a document with 2 nested arrays
我有以下 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
}
]
}
]
}
我想通过添加所有 grade_numbers
来更新每辆卡车的 average_grade
。我遇到的问题是我要添加的 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"} }
}
}])
我是否需要在查询中添加更多内容?我想更新所有 trucks.average_grades
,因为我要更新的文档中有很多。
您不能使用 aggregation
来更新文档,但您绝对可以使用它来获取要用于更新的数据。首先,我注意到 grades
数组中的 grade
对象周围缺少一些 {}
。您可能需要仔细检查您的文档结构是否与发布的一样。其次,您的聚合查询存在一些问题。
$avg
运算符在 $group
子句中工作,而不是 $project
。
- 当你使用
$avg
时,你不需要使用$sum
。
- 你想平均
trucks.grades.grade.grade_number
,它实际上保存了成绩的数值。也就是说,您在 grades
和 grade_number
之间缺少 grade
。
如果您解决了这些问题,您将收到类似于以下内容的查询:
db.col.aggregate([
{ "$unwind": "$trucks" },
{ "$unwind": "$trucks.grades" },
{ "$group":
{
"_id": "$trucks.truck_id",
"average_grade": { "$avg": "$trucks.grades.grade_number" }
}
}
]);
对于您的示例文档,returns:
{ "_id" : "TEB5572", "average_grade" : 4 }
{ "_id" : "TEB7622", "average_grade" : 4 }
现在您可以使用此信息更新 average_grade
字段。如果您使用的是 MongoDB 2.6 或更高版本,aggregate
方法将 return 一个游标。您可以遍历该游标并相应地更新文档。
在此示例中,我搜索在其 trucks
数组中具有特定 truck_id
的文档,然后继续使用聚合查询计算的文档来更新 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});
}
我有以下 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
}
]
}
]
}
我想通过添加所有 grade_numbers
来更新每辆卡车的 average_grade
。我遇到的问题是我要添加的 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"} }
}
}])
我是否需要在查询中添加更多内容?我想更新所有 trucks.average_grades
,因为我要更新的文档中有很多。
您不能使用 aggregation
来更新文档,但您绝对可以使用它来获取要用于更新的数据。首先,我注意到 grades
数组中的 grade
对象周围缺少一些 {}
。您可能需要仔细检查您的文档结构是否与发布的一样。其次,您的聚合查询存在一些问题。
$avg
运算符在$group
子句中工作,而不是$project
。- 当你使用
$avg
时,你不需要使用$sum
。 - 你想平均
trucks.grades.grade.grade_number
,它实际上保存了成绩的数值。也就是说,您在grades
和grade_number
之间缺少grade
。
如果您解决了这些问题,您将收到类似于以下内容的查询:
db.col.aggregate([
{ "$unwind": "$trucks" },
{ "$unwind": "$trucks.grades" },
{ "$group":
{
"_id": "$trucks.truck_id",
"average_grade": { "$avg": "$trucks.grades.grade_number" }
}
}
]);
对于您的示例文档,returns:
{ "_id" : "TEB5572", "average_grade" : 4 }
{ "_id" : "TEB7622", "average_grade" : 4 }
现在您可以使用此信息更新 average_grade
字段。如果您使用的是 MongoDB 2.6 或更高版本,aggregate
方法将 return 一个游标。您可以遍历该游标并相应地更新文档。
在此示例中,我搜索在其 trucks
数组中具有特定 truck_id
的文档,然后继续使用聚合查询计算的文档来更新 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});
}