MongoDB c# драйвер найти элемент в массиве по значению поля

Я нашел способ проверить, содержит ли значение в простом массиве:

var filter = Builders<Post>.Filter.AnyEq(x => x.Tags, "mongodb");

но как найти сложный элемент со многими полями по конкретному полю ? Я нашел способ написать его с помощью метода точечной нотации с помощью BsonDocument строитель, но как я могу сделать это с лямбда-нотации ?

upd

Я думаю, что это какой-то

builderInst.AnyIn(p => p.ComplexCollection.Select(ml => ml.Id), mlIds)

но не могу проверить прямо сейчас, кто-нибудь может помочь ?

4 ответов


здесь ElemMatch

var filter = Builders<Post>.Filter.ElemMatch(x => x.Tags, x => x.Name == "test");
var res = await collection.Find(filter).ToListAsync()

вам нужно $elemMatch оператора. Вы могли бы использовать Builders<T>.Filter.ElemMatch или Any выражение:

Find(x => x.Tags.Any(t => t.Name == "test")).ToListAsync()

http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/expressions/#elemmatch


начиная с версии 2.4.2 драйверов C# интерфейс IFindFluent может использоваться для запроса элемента массива. ElemMatch нельзя использовать для массива строк напрямую, в то время как интерфейс find будет работать с простыми или сложными типами (например, 'Tags.Name') и строго набирается.

            FilterDefinitionBuilder<Post> tcBuilder = Builders<Post>.Filter;
            FilterDefinition<Post> tcFilter = tcBuilder.Eq("Tags","mongodb") & tcBuilder.Eq("Tags","asp.net");
               ...
            await myCollection.FindAsync(tcFilter);

драйвер Linq использует структуру агрегации, но для запроса без операторов агрегации поиск выполняется быстрее.

обратите внимание, что это было нарушено в предыдущих версиях водителя, поэтому ответ был недоступен во время первоначальной публикации.


вот пример, который возвращает один сложный элемент из массива (используя MongoDB.Драйвер версии v2.5.0):

Простая Модель Данных

public class Zoo
{
    public List<Animal> Animals { get; set; }
}

public class Animal
{
    public string Name { get; set; }
}

Вариант 1 (Агрегация)

public Animal FindAnimalInZoo(string animalName)
{
    var zooWithAnimalFilter = Builders<Zoo>.Filter
        .ElemMatch(z => z.Animals, a => a.Name == animalName);

    return _db.GetCollection<Zoo>("zoos").Aggregate()
        .Match(zooWithAnimalFilter)
        .Project<Animal>(
            Builders<Zoo>.Projection.Expression<Animal>(z => 
                z.Animals.FirstOrDefault(a => a.Name == animalName)))
        .FirstOrDefault(); // or .ToList() to return multiple
}

Вариант 2 (Filter & Linq) это было около 5X медленнее для меня

public Animal FindAnimalInZoo(string animalName)
{
    // Same as above
    var zooWithAnimalFilter = Builders<Zoo>.Filter
        .ElemMatch(z => z.Animals, a => a.Name == animalName);

    var zooWithAnimal = _db.GetCollection<Zoo>("zoos")
        .Find(zooWithAnimalFilter)
        .FirstOrDefault();

    return zooWithAnimal.Animals.FirstOrDefault(a => a.Name == animalName);
}