1. Обзор

В этой статье разберемся, как использовать класс Filters для запросов к MongoDB.

Класс Filters представляет собой билдер для удобного написания фильтров запросов. Фильтры — это некоторые условные операции, которые MongoDB использует для ограничения результатов.

2. Типы билдеров

Драйвер MongoDB для Java предоставляет несколько типов билдеров, упрощающих создание BSON-документов и предоставляющих удобный API для выполнения различных CRUD-операций и агрегации.

Доступны следующие билдеры:

  • Filters — фильтры запросов;

  • Projections — проекции (какие поля включить, а какие исключить из результата);

  • Sorts — критерии сортировки;

  • Updates — операции обновления;

  • Aggregates — пайплайны агрегации (aggregation pipeline);

  • Indexes — создание индексов.

Далее рассмотрим использование Filters.

3. Инициализация базы данных

Начнем с создания базы данных и коллекции user, на примере которой и будем рассматривать различные операции фильтрации.

use baeldung;
db.createCollection("user");

Заполним коллекцию user несколькими документами:

db.user.insertMany([
{
    "userId":"123",
    "userName":"Jack",
    "age":23,
    "role":"Admin"
},
{
    "userId":"456",
    "userName":"Lisa",
    "age":27,
    "role":"Admin",
    "type":"Web"
},
{
    "userId":"789",
    "userName":"Tim",
    "age":31,
    "role":"Analyst"
}]);

При выполнении успешной вставки получим следующий ответ:

{
    "acknowledged" : true,
    "insertedIds" : [
        ObjectId("6357c4736c9084bcac72eced"),
        ObjectId("6357c4736c9084bcac72ecee"),
        ObjectId("6357c4736c9084bcac72ecef")
    ]
}

4. Использование класса Filters

В классе Filters содержатся статические фабричные методы, выполняющие различные операции фильтрации в MongoDB. Каждый из этих методов возвращает экземпляры интерфейса BSON, который можно передать любому методу, ожидающему фильтр запроса.

Класс Filters — это замена QueryBuilder устаревшего API.

Методы в Filters классифицируются по типу выполняемых операций: условные, логические, работа с массивами, проверка существования поля и его типа, побитовые и геопространственные.

Рассмотрим некоторые часто используемые методы Filters.

4.1. Метод eq()

Метод Filters.eq() создает фильтр для получения документов, в которых значение поля равно указанному значению.

Для начала выполним запрос в MongoDB Shell для поиска в коллекции user документов с полем userName равным "Jack":

db.getCollection('user').find({"userName":"Jack"})

Приведенный выше запрос возвращает один документ:

{
    "_id" : ObjectId("6357c4736c9084bcac72eced"),
    "userId" : "123",
    "userName" : "Jack",
    "age" : 23.0,
    "role" : "Admin"
}

Далее напишем аналогичный запрос с использованием Filters:

Bson filter = Filters.eq("userName", "Jack");
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

Можно заметить, что метод Filters.eq() возвращает тип BSON, который затем передается в метод find() в качестве фильтра.

Также есть метод Filters.ne(), который прямо противоположен методу Filters.eq() — выбираются все документы со значением поля не равным указанному значению:

Bson filter = Filters.ne("userName", "Jack");
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

4.2. Метод gt()

Метод Filters.gt() создает фильтр для получения документов, в которых значение поля больше заданного значения.

Рассмотрим следующий пример:

Bson filter = Filters.gt("age", 25);
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

В приведенном примере извлекаются документы, в которых возраст (age) превышает 25 лет. 

Аналогично методу Filters.gt(), есть метод Filters.lt(), который соответствует документам, имеющим значение поля меньше указанного:

Bson filter = Filters.lt("age", 25);
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

Существуют еще методы Filters.gte() и Filters.lte(), которые соответствуют значениям "больше или равно" и "меньше или равно" соответственно.

4.3. Метод in()

Метод Filters.in() создаёт фильтр для получения документов, в которых значение поля равно одному из значений в списке.

Давайте посмотрим на пример:

Bson filter = Filters.in("userName", "Jack", "Lisa");
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

Здесь мы получаем документы, в которых userName равно "Jack" или "Lisa".

Подобно методу Filters.in() есть метод Filters.nin(), который выбирает документы со значением поля не равным ни одному из значений списка:

Bson filter = Filters.nin("userName", "Jack", "Lisa");
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

4.4. Метод and()

Метод Filters.and() создает фильтр, выполняющий логическую операцию "И" для переданного списка фильтров.

Давайте найдем пользователей с возрастом (age) больше 25 лет и ролью (role) "Admin":

Bson filter = Filters.and(Filters.gt("age", 25), Filters.eq("role", "Admin"));
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

4.5. Метод or()

Как и следовало ожидать, метод Filters.or() выполняет логическую операцию "ИЛИ".

Давайте напишем пример, который возвращает пользователей с возрастом (age) больше 30 или ролью (role) "Admin":

Bson filter = Filters.or(Filters.gt("age", 30), Filters.eq("role", "Admin"));
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

4.6. Метод exists()

Метод Filters.exists() ищет документы, в которых присутствует указанное поле.

Bson filter = Filters.exists("type");
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

Приведенный выше код возвращает документы коллекции user, в которых есть поле type.

4.7. Метод regex()

Наконец, метод Filters.regex() проверяет поле документа на соответствие заданному регулярному выражению.

Bson filter = Filters.regex("userName", "a");
FindIterable<Document> documents = collection.find(filter);

MongoCursor<Document> cursor = documents.iterator();
while (cursor.hasNext()) {
    System.out.println(cursor.next());
}

Здесь мы извлекаем все документы, в которых userName соответствует регулярному выражению "a".

Мы рассмотрели некоторые из наиболее часто используемых операторов фильтрации. В качестве фильтра в методе find() можно использовать любую комбинацию операторов фильтрации.

Более того, фильтры могут использоваться и в других местах, например, в пайплайне агрегации, в методах deleteOne() и updateOne() и др.

5. Заключение

В этой статье мы обсудили, как использовать билдер Filters для выполнения операций фильтрации коллекций MongoDB. 

Полный код всех примеров доступен на GitHub.


На пути от монолита к микросервисам нас ожидают множество мелких неприятностей, которые могут стать серьезной проблемой по мере развития проекта. Скоро пройдет открытый урок, на котором мы рассмотрим, как легко и изящно можно их преодолеть с помощью инструментов от Spring Cloud. Регистрируйтесь по ссылке.

Комментарии (1)


  1. kpmy
    10.12.2022 00:02

    Кажется, это слабее чем QueryDSL + Morphia.