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);
}