C# MongoDB - 如何更新嵌套数组元素

4

我有以下JSON结构表示一个项目

{
    Id: "a",
    Array1: [{
        Id: "b",
        Array2: [{
            Id: "c",
            Array3: [
                {...}
            ]
        }]
    }]
}

我需要能够用新项替换Array2中的数组元素,或者仅用新数组替换Array3

以下是我的代码,用于替换Array2中的数组项:

await Collection.UpdateOneAsync(
    item => item.Id.Equals("a") &&
    item.Array1.Any(a => a.Id.Equals("b")) &&
    item.Array1[-1].Array2.Any(b => b.Id.Equals("c")),
    Builders<Item>.Update.Set(s => s.Array1[-1].Array2[-1], newArray2Item)
);

当执行这段代码时,我遇到了以下错误:
"A write operation resulted in an error.
 Too many positional (i.e. '$') elements found in path 'Array1.$.Array2.$'"

这是我用来替换Array2中的Array3的代码:

await Collection.UpdateOneAsync(
        item => item.Id.Equals("a") &&
        item.Array1.Any(a => a.Id.Equals("b")) &&
        item.Array1[-1].Array2.Any(b => b.Id.Equals("c")),
        Builders<Item>.Update.Set(s => s.Array1[-1].Array2[-1].Array3, newArray3)
    );

以下是错误信息:

"A write operation resulted in an error.
 Too many positional (i.e. '$') elements found in path 'Array1.$.Array2.$.Array3'"

我正在使用C# MongoDB驱动程序版本2.5.0和MongoDB版本3.6.1。
我发现了这个Jira工单Positional Operator Matching Nested Arrays,它说问题已经解决,并建议使用以下语法进行更新。
Update all matching documents in nested array:

db.coll.update({}, {$set: {“a.$[i].c.$[j].d”: 2}}, {arrayFilters: [{“i.b”: 0}, {“j.d”: 0}]})
Input: {a: [{b: 0, c: [{d: 0}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}
Output: {a: [{b: 0, c: [{d: 2}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}

所以我把它转换成了我的元素:
db.getCollection('Items').update(
{"Id": "a"},
{$set: {"Array1.$[i].Array2.$[j].Array3": [newArray3]}}, 
{arrayFilters: 
    [
        {"i.Id": "b"}, 
        {"j.Id": "c"}
    ]}
)

并且收到了以下错误:

cannot use the part (Array1 of Array.$[i].Array2.$[j].Array3) to traverse the element

有没有关于如何解决这个错误的想法?

1
虽然不太美观,但你可以通过使用字符串来编写更新内容,就像在 shell 中编写一样,然后将其传递给 Update() 方法作为一种快捷方式。 - dnickless
1
这就是为什么我提供了 Jira 的样例。它仍然不起作用。 - Liran Friedman
1
你需要一个更新的客户端才能使其工作(尝试使用分发的“mongo.exe” shell):https://dev59.com/6Kbja4cB1Zd3GeqPjqnI - dnickless
1
我无法在C#中使用mongo.exe...你发给我的链接是关于robomongo的。 - Liran Friedman
1
我知道。 ;) 你在示例中提供的最后一个查询是基于字符串的,你应该能够在 mongo.exe 中运行它而不会出现错误。这就是我想说的。一旦你让查询正常工作,你就可以使用过滤器和更新部分来创建一个 C# 版本。 - dnickless
1
请点击这里这里查看。要运行它,我只需要运行这个命令 db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } ) - Liran Friedman
1个回答

8

这是你所需要的C#版本:

var filter = Builders<Item>.Filter.Eq("Id", "a");
var update = Builders<Item>.Update.Set("Array1.$[i].Array2.$[j].Array3", new[] { new Item { Id = "d" } });
var arrayFilters = new List<ArrayFilterDefinition> { new JsonArrayFilterDefinition<Item>("{'i.Id': 'b'}"), new JsonArrayFilterDefinition<Item>("{'j.Id': 'c'}") };
var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };
collection.UpdateOne(filter, update, updateOptions);

1
从C#无法工作,但从Studio 3T可以正常工作,有什么想法为什么吗?它不会给出错误,并且看起来命令已经执行了,但更新没有应用... - Liran Friedman
1
找到了,它在C:\ data \ log \ mongod.log下,但我还需要执行db.setLogLevel(5)[SetLogLevel](https://docs.mongodb.com/manual/reference/method/db.setLogLevel/)。 - Liran Friedman
1
现在它可以工作了,原来我需要像这样设置id var filter = Builders<Setup>.Filter.Eq("_id", new ObjectId(configurationDevice.SetupId)); - Liran Friedman
1
不用谢,是的,那听起来非常正确。我的示例是基于您上面提供的JSON样本。但是在处理基于字符串的查询时,C#驱动程序不会翻译任何属性名称。 - dnickless
1
你能否请尝试并帮我解决另一个关于如何删除项的问题?该问题已在此处发表。 - Liran Friedman
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接