MongoDB更新文档数组并用替换文档数组进行替换。

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

MongoDB update array of documents and replace by an array of replacement documents

问题

在MongoDB中,使用数组的替换字段(文档)数组批量更新(upsert)文档是可能的吗?

基本上,想要摆脱伪代码示例中的for循环:

for user in users {
  db.users.replaceOne(
      { "name" : user.name },
      user,
      { "upsert": true }
}

updateMany文档只记录了以下情况,其中所有文档都以相同的方式进行更新:

db.collection.updateMany(
   <query>,
   { $set: { status: "D" }, $inc: { quantity: 2 } },
   ...
)

我正在尝试更新(upsert)一个文档数组,其中每个文档都有自己的替换字段集合:

updateOptions := options.UpdateOptions{}
updateOptions.SetUpsert(true)
updateOptions.SetBypassDocumentValidation(false)
_, error := collection.Col.UpdateMany(ctx, bson.M{"name": bson.M{"$in": names}}, bson.M{"$set": users}, &updateOptions)

其中users是一个文档数组:

[
{ "name": "A", ...further fields},
{ "name": "B", ...further fields},
...
]

显然,对于这种情况,不能使用$set,因为我收到以下错误:Error while bulk writing *v1.UserCollection (FailedToParse) Modifiers operate on fields but we found type array instead.

非常感谢您的帮助!

英文:

Is it possible to bulk update (upsert) an array of documents with MongoDB by an array of replacement fields (documents)?

Basically to get rid of the for loop in this pseudo code example:

for user in users {
  db.users.replaceOne(
      { &quot;name&quot; : user.name },
      user,
      { &quot;upsert&quot;: true }
}

The updateMany documentation only documents the following case where all documents are being updated in the same fashion:

db.collection.updateMany(
   &lt;query&gt;,
   { $set: { status: &quot;D&quot; }, $inc: { quantity: 2 } },
   ...
)

I am trying to update (upsert) an array of documents where each document has it's own set of replacement fields:

updateOptions := options.UpdateOptions{}
updateOptions.SetUpsert(true)
updateOptions.SetBypassDocumentValidation(false)
_, error := collection.Col.UpdateMany(ctx, bson.M{&quot;name&quot;: bson.M{&quot;$in&quot;: names}}, bson.M{&quot;$set&quot;: users}, &amp;updateOptions)

Where users is an array of documents:

[
{ &quot;name&quot;: &quot;A&quot;, ...further fields},
{ &quot;name&quot;: &quot;B&quot;, ...further fields},
...
]

Apparently, $set cannot be used for this case since I receive the following error: Error while bulk writing *v1.UserCollection (FailedToParse) Modifiers operate on fields but we found type array instead.

Any help is highly appreciated!

答案1

得分: 3

你可以使用Collection.BulkWrite()方法。

由于你想要对每个文档进行不同的更新,所以你需要为每个文档更新准备一个不同的mongo.WriteModel

你可以使用mongo.ReplaceOneModel来替换单个文档。你可以按以下方式构建它们:

wm := make([]mongo.WriteModel, len(users))
for i, user := range users {
    wm[i] = mongo.NewReplaceOneModel().
        SetUpsert(true).
        SetFilter(bson.M{"name": user.name}).
        SetReplacement(user)
}

然后,你可以使用以下方式一次性执行所有的替换操作:

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

是的,这里也有一个循环,但这是为了准备我们要执行的写入任务。所有的任务都通过一次调用发送到数据库,数据库可以在可能的情况下并行执行它们。这比为每个文档单独调用Collection.ReplaceOne()要快得多。

英文:

You may use Collection.BulkWrite().

Since you want to update each document differently, you have to prepare a different mongo.WriteModel for each document update.

You may use mongo.ReplaceOneModel for individual document replaces. You may construct them like this:

wm := make([]mongo.WriteModel, len(users)
for i, user := range users {
    wm[i] = mongo.NewReplaceOneModel().
        SetUpsert(true).
        SetFilter(bson.M{&quot;name&quot;: user.name}).
        SetReplacement(user)
}

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

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

Yes, here we too have a loop, but that is to prepare the write tasks we want to carry out. All of them is sent to the database with a single call, and the database is "free" to carry them out in parallel if possible. This is likely to be significantly faster that calling Collection.ReplaceOne() for each document individually.

huangapple
  • 本文由 发表于 2021年6月28日 15:58:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/68159623.html
匿名

发表评论

匿名网友

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

确定