Фильтрация данных

Последнее обновление: 27.10.2022

При выборке данных в методы Find()/FindAsync() передается объект BsonDocument, который устанавливает параметры фильтрации. Пустой BsonDocument позволяет выбрать все документы. Но мы можем конкретизировать выборку. Допустим, в коллекции содержатся следующие документы:

{ "_id" : ObjectId("63596dc76348749cac779373"), "Name" : "Tom", "Age" : 38, "Languages" : ["english", "german", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779374"), "Name" : "Bob", "Age" : 42, "Languages" : ["english"] }
{ "_id" : ObjectId("63596dc76348749cac779375"), "Name" : "Sam", "Age" : 25, "Languages" : ["english", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779376"), "Name" : "Alice", "Age" : 33 }
{ "_id" : ObjectId("63596dc76348749cac779377"), "Name" : "Tom", "Age" : 33, "Languages" : ["english"] }

Выберем все документы, где поле "Name" равно "Tom":

using MongoDB.Bson;
using MongoDB.Driver;

MongoClient client = new MongoClient("mongodb://localhost:27017");

var db = client.GetDatabase("test");
var collection = db.GetCollection<BsonDocument>("users");

// определяем фильтр - находим все документы, где Name = "Tom"
var filter = new BsonDocument { { "Name", "Tom" } };

List users = await collection.Find(filter).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine(user);
}

Здесь в качестве фильтра передается объект new BsonDocument { { "Name", "Tom" } }, то есть мы выбираем все документы, в которых Name="Tom". В итоге мы получим следующий вывод:

{ "_id" : ObjectId("63596dc76348749cac779373"), "Name" : "Tom", "Age" : 38, "Languages" : ["english", "german", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779377"), "Name" : "Tom", "Age" : 33, "Languages" : ["english"] }

Можно создавать и более сложные критерии фильтрации. Например, найдем все документы, где одновременно и "Name"="Tom", и "Age"=33:

using MongoDB.Bson;
using MongoDB.Driver;

MongoClient client = new MongoClient("mongodb://localhost:27017");

var db = client.GetDatabase("test");
var collection = db.GetCollection<BsonDocument>("users");

// определяем фильтр - находим все документы, где Name = "Tom" и "Age" = 33
var filter = new BsonDocument { { "Name", "Tom" }, { "Age", 33 } };

List users = await collection.Find(filter).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine(user);
}

В данном случае BsonDocument-фильтр содержит два элемента:

var filter = new BsonDocument { { "Name", "Tom" }, { "Age", 33 } };

И документы выборки должны соответствовать обоим этим элементам. Так, в данном случае мы получим следующий документ:

{ "_id" : ObjectId("63596dc76348749cac779377"), "Name" : "Tom", "Age" : 33, "Languages" : ["english"] }

Операторы выборки

Кроме использования свойств мы также можем применять в фильтрах специальные условные операторы. Они задают условие, которому должно соответствовать значение поля документа:

  • $eq (равно)

  • $ne (не равно)

  • $gt (больше чем)

  • $lt (меньше чем)

  • $gte (больше или равно)

  • $lte (меньше или равно)

  • $in определяет массив значений, одно из которых должно иметь поле документа

  • $nin определяет массив значений, которые не должно иметь поле документа

Например, найдем все документы, где "Name" НЕ равно "Tom":

using MongoDB.Bson;
using MongoDB.Driver;

MongoClient client = new MongoClient("mongodb://localhost:27017");

var db = client.GetDatabase("test"); 
var collection = db.GetCollection<BsonDocument>("users");

// определяем фильтр - находим все документы, где Name != "Tom"
var filter = new BsonDocument { { "Name", new BsonDocument("$ne", "Tom") } };

var users = await collection.Find(filter).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine(user);
}

Условие задается в виде вложенного документа BsonDocument, где вместо имени элемента применяется условный оператор выборки

var filter = new BsonDocument { { "Name", new BsonDocument("$ne", "Tom") } };

И в данном случае мы получим следующий консольный вывод:

{ "_id" : ObjectId("63596dc76348749cac779374"), "Name" : "Bob", "Age" : 42, "Languages" : ["english"] }
{ "_id" : ObjectId("63596dc76348749cac779375"), "Name" : "Sam", "Age" : 25, "Languages" : ["english", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779376"), "Name" : "Alice", "Age" : 33 }

Или найдем все документы, где Age больше 33:

var filter = new BsonDocument { { "Age", new BsonDocument("$gt", 33) } };

var users = await collection.Find(filter).ToListAsync();

Или более сложное условие - найдем документы, где Age больше 33 и Name не равно "Tom":

var filter = new BsonDocument { { "Age", new BsonDocument("$gt", 33) }, { "Name", new BsonDocument("$ne", "Tom") } };

Операторы $in и $nin позволяют проверить на соответствие одному из значений некоторого диапазона. Например, найдем документы, где Age равен 33 или 25:

var filter = new BsonDocument { { "Age", new BsonDocument("$in", new BsonArray { 33, 25}) } };

Логические операторы

Логические операторы выполняются над условиями выборки:

  • $or: соединяет два условия, и документ должен соответствовать одному из этих условий

  • $and: соединяет два условия, и документ должен соответствовать обоим условиям

  • $not: документ должен НЕ соответствовать условию

  • $nor: соединяет два условия, и документ должен НЕ соответстовать обоим условиям

Или, например, зададим фильтр для выбора документов, у которых поле "Age" имеет значение от 33 и выше, либо поле "Name" имеет значение "Tom":

var filter = new BsonDocument("$or", new BsonArray{

    new BsonDocument("Age",new BsonDocument("$gte", 33)),
    new BsonDocument("Name", "Tom")
});

var users = await collection.Find(filter).ToListAsync();

Здесь применяется оператор $or. Он выбирает документы, которые соответствуют одному из условий в массиве BsonArray. Так, в данном случае мы получим следующий результат:

{ "_id" : ObjectId("63596dc76348749cac779373"), "Name" : "Tom", "Age" : 38, "Languages" : ["english", "german", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779374"), "Name" : "Bob", "Age" : 42, "Languages" : ["english"] }
{ "_id" : ObjectId("63596dc76348749cac779376"), "Name" : "Alice", "Age" : 33 }
{ "_id" : ObjectId("63596dc76348749cac779377"), "Name" : "Tom", "Age" : 33, "Languages" : ["english"] }

Оператор $and, напротив, выбирает документы, которые соответствуют всем условиям в BsonArray. Например, выберем документы, где одновременно поле "Age" имеет значение от 33 и выше и поле "Name" имеет значение "Tom":

var filter = new BsonDocument("$and", new BsonArray{

    new BsonDocument("Age",new BsonDocument("$gte", 33)),
    new BsonDocument("Name", "Tom")
});

var users = await collection.Find(filter).ToListAsync();

Консольный вывод программы:

{ "_id" : ObjectId("63596dc76348749cac779373"), "Name" : "Tom", "Age" : 38, "Languages" : ["english", "german", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779377"), "Name" : "Tom", "Age" : 33, "Languages" : ["english"] }

Проверка на отсутствие поля. Оператор $exists

Документы могут иметь разный набор полей, что, если нам надо получить те документы, где нет какого-то поля? В этом случае нам надо найти те документы, где данное поле имеет значение BsonNull. Например, найдем документы, где НЕ определен массив Languages:

var filter = new BsonDocument("Languages", BsonNull.Value); // где Languages отсутствует

var users = await collection.Find(filter).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine(user);
}

Консольный вывод программы:

{ "_id" : ObjectId("63596dc76348749cac779376"), "Name" : "Alice", "Age" : 33 }

Или, наоборот, найдем все документы, где массив Languages определен:

var filter = new BsonDocument("Languages", new BsonDocument { {"$ne", BsonNull.Value } });

Аналогично работает оператор $exists - он позволяет извлечь только те документы, в которых определенное поле присутствует или отсутствует. Например, вернем все документы, в который есть поле Languages:

var filter = new BsonDocument("Languages", new BsonDocument { { "$exists", true } });

Если мы укажем у оператора $exists в качестве параметра false, то запрос вернет нам только те документы, в которых не определено поле Languages.

var filter = new BsonDocument("Languages", new BsonDocument { { "$exists", false } });

Поиск по массивам

Ряд операторов предназначены для работы с массивами:

  • $all: определяет набор значений, которые должны иметься в массиве

  • $size: определяет количество элементов, которые должны быть в массиве

  • $elemMatch: определяет условие, которым должны соответствовать элементы в массиве

Например, найдем все документы, где в массиве Languages есть значения "english" и "spanish":

var filter = new BsonDocument("Languages", new BsonDocument { {"$all", new BsonArray { "english", "spanish"} } });

var users = await collection.Find(filter).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine(user);
}

Консольный вывод:

{ "_id" : ObjectId("63596dc76348749cac779373"), "Name" : "Tom", "Age" : 38, "Languages" : ["english", "german", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779375"), "Name" : "Sam", "Age" : 25, "Languages" : ["english", "spanish"] }

Или найдем документы, где в массиве Languages только 1 элемент:

var filter = new BsonDocument("Languages", new BsonDocument { {"$size", 1 } });

Соответствие регулярному выражению. Оператор $regex

Оператор $regex задает регулярное выражение, которому должно соответствовать значение поля. Например, пусть поле Name заканчивается на букву "m":

var filter = new BsonDocument("Name", new BsonDocument { {"$regex", "m$" } });

var users = await collection.Find(filter).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine(user);
}

Консольный вывод в данном случае:

{ "_id" : ObjectId("63596dc76348749cac779373"), "Name" : "Tom", "Age" : 38, "Languages" : ["english", "german", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779375"), "Name" : "Sam", "Age" : 25, "Languages" : ["english", "spanish"] }
{ "_id" : ObjectId("63596dc76348749cac779377"), "Name" : "Tom", "Age" : 33, "Languages" : ["english"] }

Важно понимать, что $regex принимает не просто строки, а именно регулярные выражения.

Получение Poco-объектов

Несмотря на то, что в примерах выше мы получали объекты BsonDocument, но точно также можно получать объекты стандартных классов C#, которые описывают данные:

using MongoDB.Bson;
using MongoDB.Driver;

MongoClient client = new MongoClient("mongodb://localhost:27017");

var db = client.GetDatabase("test"); 
var collection = db.GetCollection<Person>("users");

// определяем фильтр - находим все документы, где Name = "Tom"
var users = await collection.Find(new BsonDocument("Name", "Tom")).ToListAsync();
foreach (var user in users)
{
    Console.WriteLine($"{user.Name} - {user.Age}");
    if (user.Languages != null)
        Console.WriteLine(string.Join(",", user.Languages));
}

class Person
{
    public ObjectId Id { get; set; }
    public string Name { get; set; } = "";
    public int Age { get; set; }

    public List<string>? Languages { get; set; }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850