例如,我有一个父母的集合:
class Parent{
public string ParentKey {get;set;}
public IEnumerable<Child> Children {get;set;}
}
class Child{
public string ChildKey {get;set;}
public IEnumerable<GrandChild> GrandChildren {get;set;}
}
class GrandChild {
public string GrandChildKey {get;set;}
public IEnumerable<GreatGrandChild> GreatGrandChildren {get;set;}
}
class GreatGrandChild {
public string GreatGrandChildKey {get;set;}
public string SomeValue {get;set;}
}
我可以像这样在子级别上进行一些推拉:
var filter = Builders<Parent>.Filter.Eq(p => p.ParentKey, "some-parent-key");
var pushDefinition = Builders<Parent>.Push(p => p.Children, newChild);
但我不知道如何从孙子和更深层次执行任何操作。至少我对可以使用的过滤器有一个想法:
var filter = Builders<Parent>.Filter.And(
Builders<Parent>.Filter.Eq(p => p.ParentKey, "some-parent-key"),
Builders<Parent>.Filter.ElemMatch(p => p.Children,
Builders<Child>.Filter.Eq(c => c.ChildKey, "some-child-key"))
);
更新 我发现我可以使用字符串作为目标字段的路径,但我宁愿使用 Lambda 之类的东西来更轻松地重构:
var pushDefinition = Builders<Parent>.Push("Children.$.GrandChildren", newGrandChild);
您应该需要一个嵌套的
.ElemMatch
来访问和比较嵌套元素。
var filter = Builders<Parent>.Filter.And(
Builders<Parent>.Filter.Eq(p => p.ParentKey, "<parentKey>"),
Builders<Parent>.Filter.ElemMatch(p => p.Children,
Builders<Child>.Filter.And(
Builders<Child>.Filter.Eq(c => c.ChildKey, "<childKey>"),
Builders<Child>.Filter.ElemMatch(c => c.GrandChildren,
Builders<GrandChild>.Filter.Eq(c => c.GrandChildKey, "<grandChildKey>")
)
)
)
);
要将新实例推入嵌套数组(我演示了将元素推入
greatGrandChildren
数组的示例),您需要使用 $[<identifier>]
(位置过滤运算符。
var pushDefinition = Builders<Parent>.Update.Push("children.$[c].grandChildren.$[gc].greatGrandChildren",
<new GreatGrandChild instance>);
var result = await _collection.UpdateOneAsync(filter, pushDefinition,
new UpdateOptions
{
ArrayFilters = new[]
{
new BsonDocumentArrayFilterDefinition<BsonDocument>(
new BsonDocument("c.childKey", childKey)
),
new BsonDocumentArrayFilterDefinition<BsonDocument>(
new BsonDocument("gc.grandChildKey", grandChildKey)
),
}
});