使用MongoDB C#驱动程序从父子层次结构中查找并更新节点

HaB*_*aBo 9 c# mongodb mongodb-query mongodb-.net-driver

我有一个分层的类别文档,如父母 - 儿童 - 儿童等......

{
    id: 1,
    value: {

    }Children: [{
        id: 2,
        value: {

        }Children: [{
            id: 3,
            value: {

            }Children: [{
                id: 4,
                value: {

                }Children: [{
                    id: 5,
                    value: {

                    }Children: [{
                        id: 6,
                        value: {

                        }Children: [{
                            id: 7,
                            value: {

                            }Children: []
                        }]
                    }]
                }]
            }]
        }]
    }]
}
Run Code Online (Sandbox Code Playgroud)

在这样的文档中,使用MongoDB C#驱动程序,我该如何找到一个节点 Id = x

我试过这样的事

var filter = Builders<Type>.Filter.Eq(x => x.Id, 3);
                var node = mongoDbRepository.GetOne(filter) ??
                             mongoDbRepository.GetOne(Builders<Type>.Filter.Where(x => x.Children.Any(c=>c.Id == 3)));
Run Code Online (Sandbox Code Playgroud)

但这仅涵盖两个层面.在我的例子中,我有7个级别,我没有对级别深度的限制

一旦我找到该节点,我需要更新该节点.

MongoDB文档讨论了分层文档,但不包括我的场景.

Dmi*_*Zyr 3

在你的情况下,如果你

没有关卡深度限制

您无法创建更新查询。您必须更改商店数据的架构:

https://docs.mongodb.com/v3.2/tutorial/model-tree-structs/

如果深度是固定的:

public class TestEntity
{
    public int Id { get; set; }
    public TestEntity[] Value { get; set; }
}

class Program
{
    static void Main()
    {
        const string connectionString = "mongodb://localhost:27017";
        var client = new MongoClient(connectionString);

        var db = client.GetDatabase("TestEntities");
        var collection = db.GetCollection<TestEntity>("Entities");

        collection.InsertOne(CreateTestEntity(1, CreateTestEntity(2, CreateTestEntity(3, CreateTestEntity(4)))));
        const int selctedId = 3;
        var update = Builders<TestEntity>.Update.AddToSet(x => x.Value, CreateTestEntity(9));

        var depth1 = Builders<TestEntity>.Filter.Eq(x => x.Id, selctedId);
        var depth2 = Builders<TestEntity>.Filter.Where(x => x.Value.Any(item => item.Id == selctedId));
        var depth3 = Builders<TestEntity>.Filter.Where(x => x.Value.Any(item => item.Value.Any(item2 => item2.Id == selctedId)));

        var filter = depth1 | depth2 | depth3;

        collection.UpdateMany(filter, update);

        // if you need update document on same depth that you match it in query (for example 3 as selctedId), 
        // you must make 2 query (bad approach, better way is change schema):
        //var testEntity = collection.FindSync(filter).First();
        //testEntity.Value[0].Value[0].Value = new[] {CreateTestEntity(9)}; //todo you must calculate depth what you need in C#
        //collection.ReplaceOne(filter, testEntity);
    }

    private static TestEntity CreateTestEntity(int id, params TestEntity[] values)
    {
        return new TestEntity { Id = id, Value = values };
    }
}
Run Code Online (Sandbox Code Playgroud)