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})
Возвращенные данные будут упорядочены с учетом дела. Это означает, например, что заглавная буква « B»
будет рассматриваться перед строчной буквой « a»
:
[
{
_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 .