如何在Mongo中使用一个查询更新多个记录,这些记录基于不同的键?

huangapple go评论117阅读模式
英文:

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),我的 filterupdate 应该是什么?

谢谢你的帮助。

英文:

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)

相关链接:https://stackoverflow.com/questions/68159623/mongodb-update-array-of-documents-and-replace-by-an-array-of-replacement-documen/68159870#68159870

英文:

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{&quot;_id&quot;: &quot;1&quot;}).SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: &quot;P0-A0&quot;}}),
	mongo.NewUpdateOneModel().SetFilter(bson.M{&quot;_id&quot;: &quot;2&quot;}).SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: &quot;P0-A1&quot;}}),
	mongo.NewUpdateOneModel().SetFilter(bson.M{&quot;_id&quot;: &quot;3&quot;}).SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: &quot;P0-A2&quot;}}),
	mongo.NewUpdateOneModel().SetFilter(bson.M{&quot;_id&quot;: &quot;4&quot;}).SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: &quot;P0-A3&quot;}}),
	mongo.NewUpdateOneModel().SetFilter(bson.M{&quot;_id&quot;: &quot;5&quot;}).SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: &quot;P0-A4&quot;}}),
	mongo.NewUpdateOneModel().SetFilter(bson.M{&quot;_id&quot;: &quot;6&quot;}).SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: &quot;P0-A5&quot;}}),
}

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{&quot;_id&quot;: id}).
		SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: newStatus}})
}

wm := []mongo.WriteModel{
	create(&quot;1&quot;, &quot;P0-A0&quot;),
	create(&quot;2&quot;, &quot;P0-A1&quot;),
	create(&quot;3&quot;, &quot;P0-A2&quot;),
	create(&quot;4&quot;, &quot;P0-A3&quot;),
	create(&quot;5&quot;, &quot;P0-A4&quot;),
	create(&quot;6&quot;, &quot;P0-A5&quot;),
}

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 &lt;= 6; i++ {
	newStatus := fmt.Sprintf(&quot;P0-A%d&quot;, i-1)
	wm = append(wm, mongo.NewUpdateOneModel().
		SetFilter(bson.M{&quot;_id&quot;: strconv.Itoa(i)}).
		SetUpdate(bson.M{&quot;$set&quot;: bson.M{&quot;status&quot;: newStatus}}),
	)
}

And you may execute all the updates with one call like this:

res, err := coll.BulkWrite(ctx, wm)

See related: https://stackoverflow.com/questions/68159623/mongodb-update-array-of-documents-and-replace-by-an-array-of-replacement-documen/68159870#68159870

huangapple
  • 本文由 发表于 2022年12月9日 12:52:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/74739040.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定