英文:
How would I update multiple records based on different key in Mongo in one query?
问题
如果我有类似以下的内容...
collection.InsertMany(context.TODO(), []interface{}{
bson.M{ "_id" : 1, "member" : "abc123", "status" : "P" },
bson.M{ "_id" : 2, "member" : "xyz123", "status" : "A" },
bson.M{ "_id" : 3, "member" : "lmn123", "status" : "P" },
bson.M{ "_id" : 4, "member" : "pqr123", "status" : "D" },
bson.M{ "_id" : 5, "member" : "ijk123", "status" : "P" },
bson.M{ "_id" : 6, "member" : "cde123", "status" : "A" },
} )
是否可以在一个 InsertMany 查询中应用以下更新?
[{"_id" : "1", "status" : "P0-A0"},
{"_id" : "2", "status" : "P0-A1"},
{"_id" : "3", "status" : "P0-A2"},
{"_id" : "4", "status" : "P0-A3"},
{"_id" : "5", "status" : "P0-A4"},
{"_id" : "6", "status" : "P0-A5"}]
如果可以的话,如何在 golang 中实现?
具体来说,使用 collection.UpdateMany(context.TODO(), filter, update)
,我的 filter
和 update
应该是什么?
谢谢你的帮助。
英文:
If I have something similar to the following...
collection.InsertMany(context.TODO(), []interface{}{
bson.M{ "_id" : 1, "member" : "abc123", "status" : "P" },
bson.M{ "_id" : 2, "member" : "xyz123", "status" : "A" },
bson.M{ "_id" : 3, "member" : "lmn123", "status" : "P" },
bson.M{ "_id" : 4, "member" : "pqr123", "status" : "D" },
bson.M{ "_id" : 5, "member" : "ijk123", "status" : "P" },
bson.M{ "_id" : 6, "member" : "cde123", "status" : "A" },
} )
Is is possible to apply the following update in one InsertMany query?
[{"_id" : "1", "status" : "P0-A0"},
{"_id" : "2", "status" : "P0-A1"},
{"_id" : "3", "status" : "P0-A2"},
{"_id" : "4", "status" : "P0-A3"},
{"_id" : "5", "status" : "P0-A4"},
{"_id" : "6", "status" : "P0-A5"}]
If so, how would that be done with golang?
Specifically, using collection.UpdateMany(context.TODO(), filter, update)
, what would I have for my filter
and update
?
Thanks for your help.
答案1
得分: 1
你不能通过单个Collection.UpdateMany()
调用来实现,因为你不能在不同的匹配文档上应用不同的更新文档。你需要多次调用Collection.UpdateMany()
,每次针对不同的更新文档。
如果你想要高效地使用单个调用来实现,可以使用Collection.BulkWrite()
。你需要为每个文档更新准备一个不同的mongo.WriteModel
。
以下是示例代码:
wm := []mongo.WriteModel{
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "1"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A0"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "2"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A1"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "3"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A2"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "4"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A3"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "5"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A4"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "6"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A5"}}),
}
上述代码中有太多的重复部分,你可以使用一个辅助函数来捕获它们:
create := func(id, newStatus string) *mongo.UpdateOneModel {
return mongo.NewUpdateOneModel().
SetFilter(bson.M{"_id": id}).
SetUpdate(bson.M{"$set": bson.M{"status": newStatus}})
}
wm := []mongo.WriteModel{
create("1", "P0-A0"),
create("2", "P0-A1"),
create("3", "P0-A2"),
create("4", "P0-A3"),
create("5", "P0-A4"),
create("6", "P0-A5"),
}
如果更新中有容易定义的逻辑,你可以使用循环而不是列出所有元素:
var wm []mongo.WriteModel
for i := 1; i <= 6; i++ {
newStatus := fmt.Sprintf("P0-A%d", i-1)
wm = append(wm, mongo.NewUpdateOneModel().
SetFilter(bson.M{"_id": strconv.Itoa(i)}).
SetUpdate(bson.M{"$set": bson.M{"status": newStatus}}),
)
}
你可以像这样一次性执行所有的更新:
res, err := coll.BulkWrite(ctx, wm)
英文:
You can't do it with a single Collection.UpdateMany()
call, because you can't apply different update documents on different matched documents. You would have to call Collection.UpdateMany()
many times, once for each different update document.
If you want to do it efficiently, with a single call, you may use Collection.BulkWrite()
. You have to prepare a different mongo.WriteModel
for each document update.
Here's how it could look like:
wm := []mongo.WriteModel{
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "1"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A0"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "2"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A1"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "3"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A2"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "4"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A3"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "5"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A4"}}),
mongo.NewUpdateOneModel().SetFilter(bson.M{"_id": "6"}).SetUpdate(bson.M{"$set": bson.M{"status": "P0-A5"}}),
}
There's too much "repetition" in the above slice literal, you can capture them using a helper function:
create := func(id, newStatus string) *mongo.UpdateOneModel {
return mongo.NewUpdateOneModel().
SetFilter(bson.M{"_id": id}).
SetUpdate(bson.M{"$set": bson.M{"status": newStatus}})
}
wm := []mongo.WriteModel{
create("1", "P0-A0"),
create("2", "P0-A1"),
create("3", "P0-A2"),
create("4", "P0-A3"),
create("5", "P0-A4"),
create("6", "P0-A5"),
}
Also if there's logic in the update which you can easily define, use a loop instead of listing all the elements:
var wm []mongo.WriteModel
for i := 1; i <= 6; i++ {
newStatus := fmt.Sprintf("P0-A%d", i-1)
wm = append(wm, mongo.NewUpdateOneModel().
SetFilter(bson.M{"_id": strconv.Itoa(i)}).
SetUpdate(bson.M{"$set": bson.M{"status": newStatus}}),
)
}
And you may execute all the updates with one call like this:
res, err := coll.BulkWrite(ctx, wm)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论