MongoDB C # как реализовать вложенные фильтры и проекции - PullRequest
0 голосов
/ 23 октября 2019

Учитывая следующий код C #:

    public static class TestMongo
    {
        public static void Run()
        {
            var collection = new MongoClient().GetDatabase("TestDb").GetCollection<Foo>("TestCollection");

            collection.InsertOne(new Foo()
            {
                Name = "name1",
                SomeArray = new List<Bar>()
                {
                    new Bar() { Field = "LevelA", Value = "value1"},
                    new Bar() { Field = "LevelA.LevelB", Value = "value2"},
                    new Bar() { Field = "LevelA.LevelB.LevelC", Value = ""},
                    new Bar() { Field = "LevelA.LevelD", Value = "value4"},
                }
            });
        }
    }
    public class Foo
    {
        public string Name { get; set; }
        public List<Bar> SomeArray { get; set; }
    }

    public class Bar
    {
        public string Field { get; set; }
        public string Value { get; set; }
    }

При выполнении метода Run () этот документ вставляется в Mongo:

{
   "_id":"5db015375013d8d05aed5c7b",
   "Name":"name1",
   "SomeArray":[
      {"Field":"LevelA","Value":"value1"},
      {"Field":"LevelA.LevelB","Value":"value2"},
      {"Field":"LevelA.LevelB.LevelC","Value":""},
      {"Field":"LevelA.LevelD","Value":"value4"}
   ]
}

При получении документа я хочу получить только одинмассив элемента путем фильтрации и проецирования его по Field имени. Пример:

var name = "name1";
var field = "LevelA.LevelB.LevelC";

var filter = Builders<Foo>.Filter.And(
                Builders<Foo>.Filter.Eq(w => w.Name, name),
                Builders<Foo>.Filter.ElemMatch(x => x.SomeArray, b => b.Field == field));

var projection = Builders<Foo>.Projection.ElemMatch(x => x.SomeArray, b => b.Field == field);

var output = collection.Find(filter).Project(projection).First();

Приведенный выше код работает нормально и возвращает следующий документ:

{ 
  "_id" : ObjectId("5db015275013d8d05aed5c69"), 
  "SomeArray" : [
     { "Field" : "LevelA.LevelB.LevelC", "Value" : "" }
  ] 
}

Обратите внимание, что поля в массиве представляют иерархию, разделенную точечной нотацией.

Теперь сложная часть: поскольку значение "LevelA.LevelB.LevelC" пусто, я хочу автоматически получить значение его верхнего уровня "LevelA.LevelB", а в случае, если значение "LevelA.LevelB" также пусто, я хочу, наконец,перейдите к "LevelA" и вместо этого верните его значение, все в одном запросе динамически.

Я могу придумать способы сделать это с традиционным SQL, но будет ли это достижимо с драйвером MongoDB C #?

...