Перейти к основному содержимому

Сортировка без учета регистра в MongoDB

· 5 мин. чтения

1. Обзор

По умолчанию механизм MongoDB учитывает регистр символов при сортировке извлеченных данных. Можно выполнять запросы на сортировку без учета регистра, указав Agregations или Collations .

В этом кратком руководстве мы рассмотрим два решения, использующие как MongoDB Shell, так и Java.

2. Настройка среды

Прежде всего, нам нужно запустить сервер MongoDB. Давайте используем образ Docker:

$ docker run -d -p 27017:27017 --name example-mongo mongo:latest

Это создаст новый временный контейнер Docker с именем « example-mongo », открывающий порт 27017 . Теперь нам нужно создать базовую базу данных Mongo с данными, необходимыми для тестирования решения.

Во-первых, давайте откроем Mongo Shell внутри контейнера:

$ docker exec -it example-mongo mongosh

Как только мы окажемся в оболочке, давайте переключим контекст и войдем в базу данных с именем « сортировка »:

> use sorting

Наконец, давайте вставим некоторые данные, чтобы мы могли попробовать наши операции сортировки:

> db.users.insertMany([
{name: "ben", surname: "ThisField" },
{name: "aen", surname: "Does" },
{name: "Aen", surname: "Not" },
{name: "Ben", surname: "Matter" },
])

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

3. Сортировка по умолчанию

Запустим стандартный запрос без настройки:

> db.getCollection('users').find({}).sort({name:1})

Возвращенные данные будут упорядочены с учетом дела. Это означает, например, что заглавная буква « будет рассматриваться перед строчной буквой « :

[
{
_id: ..., name: 'Aen', surname: 'Not'
},
{
_id: ..., name: 'Ben', surname: 'Matter'
},
{
_id: ..., name: 'aen', surname: 'Does'
},
{
_id: ..., name: 'ben', surname: 'ThisField'
}
]

Давайте теперь посмотрим, как мы можем сделать наши сортировки нечувствительными к регистру, чтобы Бен и Бен отображались вместе.

4. Сортировка без учета регистра в Mongo Shell

4.1. Сортировка с использованием сопоставления

Давайте попробуем использовать MongoDB Collation . Доступный только в MongoDB 3.4 и последующих версиях, он включает языковые правила для сравнения строк.

Параметр локали Collation ICU определяет, как база данных выполняет сортировку. Давайте использовать локаль «en» (английский) : ``

> db.getCollection('users').find({}).collation({locale: "en"}).sort({name:1})

Это дает вывод, в котором имена сгруппированы по буквам:

[
{
_id: ..., name: 'aen', surname: 'Does'
},
{
_id: ..., name: 'Aen', surname: 'Not'
},
{
_id: ..., name: 'ben', surname: 'ThisField'
},
{
_id: ..., name: 'Ben', surname: 'Matter'
}
]

4.2. Сортировка с использованием агрегации

Давайте теперь воспользуемся функцией агрегирования :

> db.getCollection('users').aggregate([{
"$project": {
"name": 1,
"surname": 1,
"lowerName": {
"$toLower": "$name"
}
}
},
{
"$sort": {
"lowerName": 1
}
}
])

Используя функциональность $project , мы добавляем поле lowerName в качестве строчной версии поля имени . Это позволяет нам сортировать по этому полю. Это даст нам объект результата с дополнительным полем в желаемом порядке сортировки:

[
{
_id: ..., name: 'aen', surname: 'Does', lowerName: 'aen'
},
{
_id: ..., name: 'Aen', surname: 'Not', lowerName: 'aen'
},
{
_id: ..., name: 'ben', surname: 'ThisField', lowerName: 'ben'
},
{
_id: ..., name: 'Ben', surname: 'Matter', lowerName: 'ben'
}
]

5. Сортировка без учета регистра в Java

Попробуем реализовать те же методы на Java.

5.1. Стандартный код конфигурации

Давайте сначала добавим зависимость mongo-java-driver :

<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.10</version>
</dependency>

Затем давайте подключимся с помощью MongoClient :

MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("sorting");
MongoCollection<Document> collection = db.getCollection("users");

5.2. Сортировка с использованием сортировки в Java

Давайте посмотрим, как можно реализовать решение Collation на Java:

FindIterable<Document> nameDoc = collection.find().sort(ascending("name"))
.collation(Collation.builder().locale("en").build());

Здесь мы построили сопоставление, используя локаль «en» . Затем мы передали созданный объект Collation методу сопоставления объекта FindIterable .

Далее давайте прочитаем результаты один за другим, используя MongoCursor :

MongoCursor cursor = nameDoc.cursor();
List expectedNamesOrdering = Arrays.asList("aen", "Aen", "ben", "Ben", "cen", "Cen");
List actualNamesOrdering = new ArrayList<>();
while (cursor.hasNext()) {
Document document = cursor.next();
actualNamesOrdering.add(document.get("name").toString());
}
assertEquals(expectedNamesOrdering, actualNamesOrdering);

5.3. Сортировка с использованием агрегатов в Java

Мы также можем отсортировать коллекцию с помощью Aggregation . Давайте воссоздадим нашу версию командной строки, используя Java API.

Во-первых, мы полагаемся на метод проекта для создания объекта Bson . Этот объект также будет включать поле lowerName , которое вычисляется путем преобразования каждого символа имени в нижний регистр с использованием класса Projections :

Bson projectBson = project(
Projections.fields(
Projections.include("name","surname"),
Projections.computed("lowerName", Projections.computed("$toLower", "$name"))));

Затем мы передаем агрегатному методу список, содержащий Bson предыдущего фрагмента и метод сортировки :

AggregateIterable<Document> nameDoc = collection.aggregate(
Arrays.asList(projectBson,
sort(Sorts.ascending("lowerName"))));

В этом случае, как и в предыдущем, мы могли легко прочитать результаты с помощью MongoCursor .

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

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

Мы использовали методы агрегации и сопоставления в оболочке MongoDB. В итоге мы перевели эти запросы и предоставили простую реализацию Java с использованием библиотеки mongo-java-driver .

Как всегда, полный исходный код статьи доступен на GitHub .