Драйвер Mongodb C # возвращает только совпадающие суб-документы в массиве - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть документ в этом формате:

{
    _id: ...,
    myArray: [{other: stuff}, {other: stuff}, ...],
    ...
}

Я хочу найти элементы, которые соответствуют определенным вещам, например, значение _id или поля из вложенных документов в myArray.

Я хочу вернуть документы, но с отфильтрованным MyArray, где присутствуют только соответствующие поддокументы.

Я попытался создать проекцию и включить соответствующие элементы:

_mongoContext.myDocument
    .Find(x => x.id == id & x.myArray.Any(y => myList.Contains(t.other)))
    .Project<myModel>(Builders<myModel>.Projection.Include("myArray.$"))

Это, я думаю, должно возвращать только первый элемент, который соответствует myArray вместо всех документов, а это не то, что я хочу (я хочу, чтобы все поддокументы, которые соответствуют запросу, присутствовали в возвращенном документе) .

И вообще, это даже не сработало, я получаю ошибку positional projection does not match the query document. Может быть, это потому, что я не использую FindOne?

В любом случае, как мне добиться того, что я ищу? (См. Вопрос жирным шрифтом)

1 Ответ

0 голосов
/ 09 ноября 2018

Обычно вам нужно использовать $ filter в Aggregation Framework для фильтрации вложенного массива.Однако есть более простой способ добиться этого, используя драйвер MongoDB .NET и IQueryable интерфейс.

Рассматривая простейшую модель:

public class MyModel
{
    public string _id { get; set; }
    public IEnumerable<MyNestedModel> myArray { get; set; }
}

public class MyNestedModel
{
    public string other { get; set; }
}

и следующие данные:

var m = new MyModel()
{
    _id = "1",
    myArray = new List<MyNestedModel>() {
        new MyNestedModel() {  other = "stuff" },
        new MyNestedModel() { other = "stuff" },
        new MyNestedModel() { other = "stuff2" } }
};

Col.InsertOne(m);

Вы можете просто позвонить .AsQueryable() в своей коллекции, а затем написать запрос LINQ, который будет переведен драйвером MongoDB в $filter, попробуйте:

var query = from doc in Col.AsQueryable()
            where doc._id == "1"
            select new MyModel()
            {
                _id = doc._id,
                myArray = doc.myArray.Where(x => x.other == "stuff")
            };

var result = query.ToList();

РЕДАКТИРОВАТЬ:

В качестве альтернативы вы можете написать $filter part как необработанную строку и затем использовать метод .Aggregate().Используя этот подход, вам не нужно «отображать» все свойства, однако недостатком является то, что вы теряете безопасность типов, поскольку это всего лишь строка, попробуйте:

var addFields = BsonDocument.Parse("{ \"$addFields\": { myArray: { $filter: { input: \"$myArray\", as: \"m\", cond: { $eq: [ \"$$m.other\", \"stuff\" ] } }  } } }");

var query = Col.Aggregate()
               .Match(x => x._id == "1")
               .AppendStage<MyModel>(addFields);

$addFields используется здесь дляперезаписать существующее поле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...