Записать запрос на получение информации из пн go из спецификации c структуры документа - PullRequest
0 голосов
/ 28 мая 2020

Представьте, что у меня есть такая структура документа:

DocumentOne
{
  string Id { get; set; };
  string InnerId { get; set; }
  DocumentTwo[] InnerDocuments { get; set; }
}

DocumentTwo
{
  string Id { get; set; }
  string AnotherField { get; set; }
}

Я пытаюсь написать запрос для фильтрации документов по условию DocumentOne.InnerId != DocumentTwo.Id дюйм net с помощью драйвера mongodb.

Я пытался используйте

Builder<DocumentOne>.Filter.ElemMatch(x => x.InnerDocuments, y => y.Id != ???)

, но я не могу получить доступ к InnerId в этом запросе (вопросительные знаки)

Если я попытаюсь использовать Fluent Syntax, например

database.Find(x => x.InnerDocuments.Contains(y => y.Id != x.InnerId)) 

или

database.Find(!x => x.InnerDocuments.Any(y => y.Id != x.InnerId))

Я получил сообщение об ошибке от драйвера.

Как мне нужно переписать этот запрос?

1 Ответ

0 голосов
/ 28 мая 2020

Есть 2 способа сделать это, либо путем агрегации, либо с помощью поиска с выражением .

Мы рассмотрим агрегацию, так как для меня она протекает немного проще .

Итак, начнем с того, что у нас будет 2 модели для MongoDB, как вы сказали.


    public class DocumentOne
    {
        public string Id { get; set; }
        public string InnerId { get; set; }
        public DocumentTwo[] InnerDocuments { get; set; }
    }

    public class DocumentTwo
    {
        public string Id { get; set; }
        public string AnotherField { get; set; }
    }

Затем нам понадобится вторая проекция, чтобы отслеживать события позже, когда мы развернуть внутренние документы:


    public class DocumentOneProjection
    {
        public string Id { get; set; }
        public string InnerId { get; set; }
        public DocumentTwo InnerDocuments { get; set; }
    }

Итак, мы добавим некоторые данные в MongoDB, чтобы поиграть с

var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<DocumentOne>("documents");

await database.DropCollectionAsync(collection.CollectionNamespace.CollectionName);

await collection.InsertManyAsync(new[]
{
    new DocumentOne()
    {
        Id = "1", InnerId = "10", InnerDocuments = new[]
        {
            new DocumentTwo()
            {
                Id = "11"
            }
        }
    },
    new DocumentOne()
    {
        Id = "2", InnerId = "20", InnerDocuments = new[]
        {
            new DocumentTwo()
            {
                Id = "20"
            }
        }
    },
    new DocumentOne()
    {
        Id = "3", InnerId = "30", InnerDocuments = new[]
        {
            new DocumentTwo()
            {
                Id = "30"
            },
            new DocumentTwo()
            {
                Id = "31"
            }
        }
    }
});

Затем мы сможем создать запрос агрегирования

var items = await collection.Aggregate()
    .Unwind(x => x.InnerDocuments)
    .AppendStage<BsonDocument>(
        @"{ $addFields: { matchInner: { $cmp: [ ""$InnerId"", ""$InnerDocuments._id"" ] } } }")
    .Match("{ matchInner: { $ne : 0 } }") // 0 if the two values are equivalent.
    .AppendStage<DocumentOneProjection>(
        @"{ $unset: ""matchInner"" }")
    .ToListAsync();

Этот запрос начинается с разворачивания всех внутренних документов, это создаст документ для каждого документа в массиве (https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/)

Затем он создает новое поле, для которого мы затем создадим соответствие позже, здесь используется сравнение ($ cmp - https://docs.mongodb.com/manual/reference/operator/aggregation/cmp/)

Затем мы просто сопоставляем новое поле и затем выполняем запрос, чтобы получить обратно документы.

...