如何利用MongoDB内嵌数组的值批量更新文档
MongoDB数组匹配元素的批量更新问题
需求说明
需要批量更新MongoDB文档:找到所有results数组中存在id: "a1"且somethingElse: "aa"元素的文档,将文档的total字段加上该匹配元素的value值。
示例文档:
[ { "_id": "Ox1", "results": [ {"id": "a1", "somethingElse": "aa", "value": 1}, {"id": "a2", "somethingElse": "bb", "value": 2}, {"id": "a3", "somethingElse": "cc", "value": 3} ], "total": 0 }, { "_id": "Ox2", "results": [ {"id": "a1", "somethingElse": "aa", "value": 44}, {"id": "a4", "somethingElse": "bb", "value": 4}, {"id": "a5", "somethingElse": "aa", "value": 5} ], "total": 0 }, { "_id": "Ox3", "results": [ {"id": "a2", "somethingElse": "aa", "value": 1}, {"id": "a3", "somethingElse": "aa", "value": 4}, {"id": "a4", "somethingElse": "aa", "value": 5} ], "total": 0 } ]
预期结果:
- Ox1的total变为1
- Ox2的total变为44
- Ox3不满足条件,无更新
原代码问题
原filter部分逻辑正确,但普通更新操作符无法直接引用数组中匹配元素的value值,需要使用聚合管道更新(MongoDB 4.2及以上版本支持)。
解决方案
使用聚合管道作为UpdateMany的更新参数,通过聚合操作筛选出目标元素的value值,再计算新的total。
完整Go代码如下:
import ( "context" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) func updateTotal(collection *mongo.Collection) error { // 过滤条件:匹配results数组中存在id=a1且somethingElse=aa的文档 filter := bson.D{ {Key: "results", Value: bson.D{ {Key: "$elemMatch", Value: bson.D{ {Key: "id", Value: "a1"}, {Key: "somethingElse", Value: "aa"}, }}, }}, } // 聚合管道更新:计算新的total值 update := bson.D{ {Key: "$set", Value: bson.D{ {Key: "total", Value: bson.D{ {Key: "$sum", Value: bson.A{ "$total", // 先筛选出匹配的数组元素,再取第一个的value bson.D{ {Key: "$let", Value: bson.D{ {Key: "vars", Value: bson.D{ {Key: "matched", Value: bson.D{ {Key: "$arrayElemAt", Value: bson.A{ bson.D{ {Key: "$filter", Value: bson.D{ {Key: "input", Value: "$results"}, {Key: "cond", Value: bson.D{ {Key: "$and", Value: bson.A{ bson.D{{Key: "$eq", Value: bson.A{"$$this.id", "a1"}}}, bson.D{{Key: "$eq", Value: bson.A{"$$this.somethingElse", "aa"}}}, }}, }}, }}, }, 0, }}, }}, }}, {Key: "in", Value: "$$matched.value"}, }}, }, }}, }}, }}, } // 执行批量更新 _, err := collection.UpdateMany(context.TODO(), filter, update) return err }
代码说明
- $filter:遍历
results数组,筛选出满足id="a1"且somethingElse="aa"的元素,返回匹配元素数组。 - $arrayElemAt:取筛选后数组的第一个元素(filter已确保至少有一个匹配)。
- $let:将匹配元素赋值给临时变量,方便提取其
value字段。 - $sum:将原
total值与匹配元素的value相加,得到新的total值。
内容的提问来源于stack exchange,提问作者Ezechiel
相关产品推荐
相关产品推荐

