MongoDB C# 批量更新嵌套数组元素

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

MongoDB C# Bulk Update of nested array elements

问题

以下是您提供的内容的中文翻译:

我希望有人能指点我正确的方向

我正在尝试利用MongoDB的C#驱动程序(版本2.19.1)的批量更新功能。我想要在我的集合中的所有文档中更新所有匹配旧值(在我的示例中是URL)的新值。我尝试按照MongoDB提供的示例这里的说明进行操作,即“更新多个文档”。

以下是产生错误的C#筛选器和更新语句:

public void UpdateUrlsMany(string originalUrl, string newUrl, string collectionName)
{
    var articlesCol = _database.GetCollection<Document>(collectionName);

    var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
    var update = Builders<Document>.Update.Set("Paragraphs.Images.Url", newUrl);
 
    articlesCol.UpdateMany(filter, update); // <- 错误发生在这里
}

执行更新时产生的错误。
“MongoDB.Driver.MongoBulkWriteException`1[…Document]:批量写操作导致一个或多个错误。写入错误:[ { Category : "未分类", Code : 28, Message : "无法在元素中创建字段 'Images' …“

供参考的MongoDB集合中的JSON示例如下:

[
  {
    "_id": "527c61082241f813c09c711c",
    "Paragraphs": [
      {
        "Data": "一些信息",
        "Images": [
          {
            "Title": "",
            "Url": "i/folder1/path0_1.jpg"
          }
        ]
      },
      {
        "Data": "一些信息",
        "Images": [
          {
            "Title": "一些标题…",
            "Url": "i/folder1/path0_2.jpg"
          }
        ]
      }
    ]
  },
  {
    "_id": "527c61092241f813c09c7012",
    "Paragraphs": [
      {
        "Data": "一些信息",
        "Images": [
          {
            "Title": "标题文本",
            "Url": "i/folder2/path1_1.jpg"
          },
          {
            "Title": "标题文本",
            "Url": "i/folder2/path1_2.jpg"
          }
        ]
      },
      {
        "Data": "一些信息",
        "Images": [
          {
            "Title": "标题文本…",
            "Url": "i/folder2/path2_0.jpg"
          }
        ]
      }
    ]
  }
]

感谢任何帮助 MongoDB C# 批量更新嵌套数组元素

英文:

I was hoping that someone could point me in the right direction here

I'm trying to leverage MongoDB’s C# driver (ver2.19.1) bulk update functionality. I wanted to update all matches of old value (URL in my example) with a new one in all documents within my collection.
It tried to follow directions provided by MongoDBs example provided here, “Update Many Documents”.

The C# filter and update statement as shown below but it produces an error --- I've been struggling to work out why but I believe its associated with finding and updating elements of an embedded array within my saved documents.

Here’s the code that produces the error:

public void UpdateUrlsMany(string originalUrl, string newUrl, string collectionName)
    {
        var articlesCol = _database.GetCollection&lt;Document&gt;(collectionName);

        var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
        var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.Images.Url&quot;, newUrl);
     
        articlesCol.UpdateMany(filter, update); //&lt;- error occurs here
    }

Error produced when update is executed.
“MongoDB.Driver.MongoBulkWriteException`1[…Document] : A bulk write operation resulted in one or more errors. WriteErrors: [ { Category : "Uncategorized", Code : 28, Message : "Cannot create field 'Images' in element … “

An example of the JSON housed with MongoDB collection looks like this for reference.

[
  {
    &quot;_id&quot;: &quot;527c61082241f813c09c711c&quot;,
    &quot;Paragraphs&quot;: [
      {
        &quot;Data&quot;: &quot;some info&quot;,
        &quot;Images&quot;: [
          {
            &quot;Title&quot;: &quot;&quot;,
            &quot;Url&quot;: &quot;i/folder1/path0_1.jpg&quot;
          }
        ]
      },
      {
        &quot;Data&quot;: &quot;some info&quot;,
        &quot;Images&quot;: [
          {
            &quot;Title&quot;: &quot;some title…&quot;,
            &quot;Url&quot;: &quot;i/folder1/path0_2.jpg&quot;
          }
        ]
      }
    ]
  },
  {
    &quot;_id&quot;: &quot;527c61092241f813c09c7012&quot;,
    &quot;Paragraphs&quot;: [
      {
        &quot;Data&quot;: &quot;some info&quot;,
        &quot;Images&quot;: [
          {
            &quot;Title&quot;: &quot;title text&quot;,
            &quot;Url&quot;: &quot;i/folder2/path1_1.jpg&quot;
          },
          {
            &quot;Title&quot;: &quot; title text &quot;,
            &quot;Url&quot;: &quot;i/folder2/path1_2.jpg&quot;
          }

        ]
      },
      {
        &quot;Data&quot;: &quot;some info&quot;,
        &quot;Images&quot;: [
          {
            &quot;Title&quot;: &quot;title text ….&quot;,
            &quot;Url&quot;: &quot;i/folder2/path2_0.jpg&quot;
          }
        ]
      }
  }
]

Thanks for any assistance MongoDB C# 批量更新嵌套数组元素

答案1

得分: 0

The error is because the wrapper creates a query providing a path as "Paragraphs.Images.Url". Exactly it creates:

    db.collection.updateMany(
      {
        "Paragraphs.Images.Url": "existingurl"
},
{
  $set: {
    "Paragraphs.Images.Url": "newurl"
  }
})

Thus the error "Cannot create field 'Images' in element … " since that path does not exist and it is also a nested collection. In order to make it work you need to create nested elements as:

db.collection.updateMany(
  {
    "Paragraphs.Images.Url":
      "existingurl",
  },
  {
    $set: {
      Paragraphs: {
        Images: {
          Url: "newurl",
        },
      },
    },
  }
);

Update

A potential asynchronous solution given that it can perform a mass update is as follows:

  private static async Task<UpdateResult> UpdateManyUrlAsync(string originalUrl, string newUrl, string collectionName)
        {
            var articlesCol = _database.GetCollection<Document>(collectionName);         

            var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
            var update = Builders<Document>.Update.Set("Paragraphs.$.Images.$[].Url", newUrl);

            return await collection.UpdateManyAsync(filter, update);
            
        }
英文:

The error is because the wrapper creates a query providing a path as "Paragraphs.Images.Url". Exactly it creates:

    db.collection.updateMany(
      {
        &quot;Paragraphs.Images.Url&quot;: &quot;existingurl&quot;
},
{
  $set: {
    &quot;Paragraphs.Images.Url&quot;: &quot;newurl&quot;
  }
})

Thus the error "Cannot create field 'Images' in element … “ since that path does not exist and it is also a nested collection. In order to make it work you need to create nested elements as:

db.collection.updateMany(
  {
    &quot;Paragraphs.Images.Url&quot;:
      &quot;existingurl&quot;,
  },
  {
    $set: {
      Paragraphs: {
        Images: {
          Url: &quot;newurl&quot;,
        },
      },
    },
  }
);

Update

A potential asynchronous solution given that it can perform a mass update is as follows:

  private static async Task&lt;UpdateResult&gt; UpdateManyUrlAsync(string originalUrl, string newUrl, string collectionName)
        {
            var articlesCol = _database.GetCollection&lt;Document&gt;(collectionName);         

            var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
            var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.$.Images.$[].Url&quot;, newUrl);

            return await collection.UpdateManyAsync(filter, update);
            
        }

答案2

得分: 0

以下是翻译好的内容:

问题在于当字段位于数组中时,无法直接设置字段值。

您需要使用$[<identifier>] 过滤定位操作符

要么:

db.collection.update(
  {"Paragraphs.Images.Url": /* originalUrl */},
  {
    $set: {
      "Paragraphs.$.Images.$[].Url": /* newUrl */
    }
  }
)
var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
var update = Builders<Document>.Update.Set("Paragraphs.$.Images.$[].Url", newUrl);
     
articlesCol.UpdateMany(filter, update);

或者:

db.collection.update(
  {"Paragraphs.Images.Url": /* originalUrl */},
  {
    $set: {
      "Paragraphs.$.Images.$[image].Url": /* newUrl */
    }
  },
  {
    arrayFilters: [
      {
        "image.Url": /* originalUrl */
      }
    ]
  }
)
var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
var update = Builders<Document>.Update.Set("Paragraphs.$.Images.$[image].Url", newUrl);

var arrayFilters = new[]
{
    new BsonDocumentArrayFilterDefinition<Document>(
        new BsonDocument("image.Url", originalUrl)
    )
};

articlesCol.UpdateMany(filter, update, 
    options: new UpdateOptions { ArrayFilters = arrayFilters });
英文:

The problem is that you can't directly set the field value when the field is in the array.

You need to work with $[&lt;identifier&gt;] filtered positional operator.

Either:

db.collection.update({
  &quot;Paragraphs.Images.Url&quot;: /* originalUrl */
},
{
  $set: {
    &quot;Paragraphs.$.Images.$[].Url&quot;: /* newUrl */
  }
})
var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.$.Images.$[].Url&quot;, newUrl);
     
articlesCol.UpdateMany(filter, update);

Or:

db.collection.update({
  &quot;Paragraphs.Images.Url&quot;: /* originalUrl */
},
{
  $set: {
    &quot;Paragraphs.$.Images.$[image].Url&quot;: /* newUrl */
  }
},
{
  arrayFilters: [
    {
      &quot;image.Url&quot;: /* originalUrl */
    }
  ]
})
var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.$.Images.$[image].Url&quot;, newUrl);

var arrayFilters = new[]
{
    new BsonDocumentArrayFilterDefinition&lt;Document&gt;(
        new BsonDocument(&quot;image.Url&quot;, originalUrl)
    )
};

articlesCol.UpdateMany(filter, update, 
    options: new UpdateOptions { ArrayFilters = arrayFilters });

huangapple
  • 本文由 发表于 2023年5月14日 09:28:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76245466.html
匿名

发表评论

匿名网友

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

确定