英文:
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"
}
]
}
]
}
]
感谢任何帮助
英文:
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<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); //<- 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.
[
{
"_id": "527c61082241f813c09c711c",
"Paragraphs": [
{
"Data": "some info",
"Images": [
{
"Title": "",
"Url": "i/folder1/path0_1.jpg"
}
]
},
{
"Data": "some info",
"Images": [
{
"Title": "some title…",
"Url": "i/folder1/path0_2.jpg"
}
]
}
]
},
{
"_id": "527c61092241f813c09c7012",
"Paragraphs": [
{
"Data": "some info",
"Images": [
{
"Title": "title text",
"Url": "i/folder2/path1_1.jpg"
},
{
"Title": " title text ",
"Url": "i/folder2/path1_2.jpg"
}
]
},
{
"Data": "some info",
"Images": [
{
"Title": "title text ….",
"Url": "i/folder2/path2_0.jpg"
}
]
}
}
]
Thanks for any assistance
答案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(
{
"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);
}
答案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 $[<identifier>]
filtered positional operator.
Either:
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);
Or:
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 });
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论