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

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

MongoDB C# Bulk Update of nested array elements

问题

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

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

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

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

  1. public void UpdateUrlsMany(string originalUrl, string newUrl, string collectionName)
  2. {
  3. var articlesCol = _database.GetCollection<Document>(collectionName);
  4. var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
  5. var update = Builders<Document>.Update.Set("Paragraphs.Images.Url", newUrl);
  6. articlesCol.UpdateMany(filter, update); // <- 错误发生在这里
  7. }

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

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

  1. [
  2. {
  3. "_id": "527c61082241f813c09c711c",
  4. "Paragraphs": [
  5. {
  6. "Data": "一些信息",
  7. "Images": [
  8. {
  9. "Title": "",
  10. "Url": "i/folder1/path0_1.jpg"
  11. }
  12. ]
  13. },
  14. {
  15. "Data": "一些信息",
  16. "Images": [
  17. {
  18. "Title": "一些标题…",
  19. "Url": "i/folder1/path0_2.jpg"
  20. }
  21. ]
  22. }
  23. ]
  24. },
  25. {
  26. "_id": "527c61092241f813c09c7012",
  27. "Paragraphs": [
  28. {
  29. "Data": "一些信息",
  30. "Images": [
  31. {
  32. "Title": "标题文本",
  33. "Url": "i/folder2/path1_1.jpg"
  34. },
  35. {
  36. "Title": "标题文本",
  37. "Url": "i/folder2/path1_2.jpg"
  38. }
  39. ]
  40. },
  41. {
  42. "Data": "一些信息",
  43. "Images": [
  44. {
  45. "Title": "标题文本…",
  46. "Url": "i/folder2/path2_0.jpg"
  47. }
  48. ]
  49. }
  50. ]
  51. }
  52. ]

感谢任何帮助 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:

  1. public void UpdateUrlsMany(string originalUrl, string newUrl, string collectionName)
  2. {
  3. var articlesCol = _database.GetCollection&lt;Document&gt;(collectionName);
  4. var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
  5. var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.Images.Url&quot;, newUrl);
  6. articlesCol.UpdateMany(filter, update); //&lt;- error occurs here
  7. }

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.

  1. [
  2. {
  3. &quot;_id&quot;: &quot;527c61082241f813c09c711c&quot;,
  4. &quot;Paragraphs&quot;: [
  5. {
  6. &quot;Data&quot;: &quot;some info&quot;,
  7. &quot;Images&quot;: [
  8. {
  9. &quot;Title&quot;: &quot;&quot;,
  10. &quot;Url&quot;: &quot;i/folder1/path0_1.jpg&quot;
  11. }
  12. ]
  13. },
  14. {
  15. &quot;Data&quot;: &quot;some info&quot;,
  16. &quot;Images&quot;: [
  17. {
  18. &quot;Title&quot;: &quot;some title…&quot;,
  19. &quot;Url&quot;: &quot;i/folder1/path0_2.jpg&quot;
  20. }
  21. ]
  22. }
  23. ]
  24. },
  25. {
  26. &quot;_id&quot;: &quot;527c61092241f813c09c7012&quot;,
  27. &quot;Paragraphs&quot;: [
  28. {
  29. &quot;Data&quot;: &quot;some info&quot;,
  30. &quot;Images&quot;: [
  31. {
  32. &quot;Title&quot;: &quot;title text&quot;,
  33. &quot;Url&quot;: &quot;i/folder2/path1_1.jpg&quot;
  34. },
  35. {
  36. &quot;Title&quot;: &quot; title text &quot;,
  37. &quot;Url&quot;: &quot;i/folder2/path1_2.jpg&quot;
  38. }
  39. ]
  40. },
  41. {
  42. &quot;Data&quot;: &quot;some info&quot;,
  43. &quot;Images&quot;: [
  44. {
  45. &quot;Title&quot;: &quot;title text ….&quot;,
  46. &quot;Url&quot;: &quot;i/folder2/path2_0.jpg&quot;
  47. }
  48. ]
  49. }
  50. }
  51. ]

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:

  1. db.collection.updateMany(
  2. {
  3. "Paragraphs.Images.Url": "existingurl"
  4. },
  5. {
  6. $set: {
  7. "Paragraphs.Images.Url": "newurl"
  8. }
  9. })

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:

  1. db.collection.updateMany(
  2. {
  3. "Paragraphs.Images.Url":
  4. "existingurl",
  5. },
  6. {
  7. $set: {
  8. Paragraphs: {
  9. Images: {
  10. Url: "newurl",
  11. },
  12. },
  13. },
  14. }
  15. );

Update

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

  1. private static async Task<UpdateResult> UpdateManyUrlAsync(string originalUrl, string newUrl, string collectionName)
  2. {
  3. var articlesCol = _database.GetCollection<Document>(collectionName);
  4. var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
  5. var update = Builders<Document>.Update.Set("Paragraphs.$.Images.$[].Url", newUrl);
  6. return await collection.UpdateManyAsync(filter, update);
  7. }
英文:

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

  1. db.collection.updateMany(
  2. {
  3. &quot;Paragraphs.Images.Url&quot;: &quot;existingurl&quot;
  4. },
  5. {
  6. $set: {
  7. &quot;Paragraphs.Images.Url&quot;: &quot;newurl&quot;
  8. }
  9. })

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:

  1. db.collection.updateMany(
  2. {
  3. &quot;Paragraphs.Images.Url&quot;:
  4. &quot;existingurl&quot;,
  5. },
  6. {
  7. $set: {
  8. Paragraphs: {
  9. Images: {
  10. Url: &quot;newurl&quot;,
  11. },
  12. },
  13. },
  14. }
  15. );

Update

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

  1. private static async Task&lt;UpdateResult&gt; UpdateManyUrlAsync(string originalUrl, string newUrl, string collectionName)
  2. {
  3. var articlesCol = _database.GetCollection&lt;Document&gt;(collectionName);
  4. var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
  5. var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.$.Images.$[].Url&quot;, newUrl);
  6. return await collection.UpdateManyAsync(filter, update);
  7. }

答案2

得分: 0

以下是翻译好的内容:

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

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

要么:

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

或者:

  1. db.collection.update(
  2. {"Paragraphs.Images.Url": /* originalUrl */},
  3. {
  4. $set: {
  5. "Paragraphs.$.Images.$[image].Url": /* newUrl */
  6. }
  7. },
  8. {
  9. arrayFilters: [
  10. {
  11. "image.Url": /* originalUrl */
  12. }
  13. ]
  14. }
  15. )
  1. var filter = Builders<Document>.Filter.Eq("Paragraphs.Images.Url", originalUrl);
  2. var update = Builders<Document>.Update.Set("Paragraphs.$.Images.$[image].Url", newUrl);
  3. var arrayFilters = new[]
  4. {
  5. new BsonDocumentArrayFilterDefinition<Document>(
  6. new BsonDocument("image.Url", originalUrl)
  7. )
  8. };
  9. articlesCol.UpdateMany(filter, update,
  10. 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:

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

Or:

  1. db.collection.update({
  2. &quot;Paragraphs.Images.Url&quot;: /* originalUrl */
  3. },
  4. {
  5. $set: {
  6. &quot;Paragraphs.$.Images.$[image].Url&quot;: /* newUrl */
  7. }
  8. },
  9. {
  10. arrayFilters: [
  11. {
  12. &quot;image.Url&quot;: /* originalUrl */
  13. }
  14. ]
  15. })
  1. var filter = Builders&lt;Document&gt;.Filter.Eq(&quot;Paragraphs.Images.Url&quot;, originalUrl);
  2. var update = Builders&lt;Document&gt;.Update.Set(&quot;Paragraphs.$.Images.$[image].Url&quot;, newUrl);
  3. var arrayFilters = new[]
  4. {
  5. new BsonDocumentArrayFilterDefinition&lt;Document&gt;(
  6. new BsonDocument(&quot;image.Url&quot;, originalUrl)
  7. )
  8. };
  9. articlesCol.UpdateMany(filter, update,
  10. 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:

确定