Сортировка и ограничение выдачи
Reindexer может сортировать документы по возрастанию (ASC
, используется по умолчанию) и убыванию (DESC
).
При задании условий сортировки возможно использование математических выражений.
Выражения с условиями сортировки могут содержать:
- имена полей и индексов неймспейсов;
- числа;
- функции
rank()
,abs()
,ST-Distance()
; - скобки и арифметические выражения.
Сортировка по полю
Выражения с условиями сортировки могут содержать имена полей и индексов неймспейсов (включая вложенные и поля приджойненных неймспейсов).
Сортировка по полям приджойненных неймспейсов работает только для
InnerJoin
и только если join происходит 1 к 1.
При сортировке по композитному индексу сравнение выполняется в лексикографическом порядке по входящим в него полям.
При сортировке по неиндексному полю оно должно содержать значения одного типа, либо все значения должны быть численными (
bool
,int
,int64
,float
).
Примеры:
При взаимодействии с БД через Go-коннектор для сортировки используется метод Sort()
.
// Сортировка по полю
query := db.Query("actors").Sort("id", false)
....
// Сортировка по вложенному полю
query = db.Query("actors").Sort("person.age", false)
....
// Сортировка по полю приджойненного неймспейса.
query = db.Query("actors").
InnerJoin(db.Query("cities")).On("birth_place_id", reindexer.EQ, "id").
Sort("cities.population", false)
В SQL-запросах для сортировки используется оператор ORDER BY
.
Сортировку можно выполнять по нескольким полям, указав их через запятую.
При этом сперва выполняется сортировка по первому полю, затем среди групп полей с одинаковыми значениями выполняется сортировка по второму полю и так далее.
Признак DESC
указывается для каждого поля отдельно.
Если сначала нужно вывести записи с требуемыми значениями столбца, а затем все остальные, используйте параметр FIELD
.
-- Сортировка по полю
SELECT * FROM actors ORDER BY person ASC
....
-- Сортировка по вложенному полю
SELECT * FROM actors ORDER BY `person.name` ASC
....
-- Сортировка по joined-полю
SELECT * from actors INNER JOIN (select * from cities) ON birth_place_id.id ORDER BY cities.population ASC
....
-- Сортировка с использованием FIELD
SELECT * FROM media_items WHERE 'ratings.imdb' > 9.2 ORDER BY FIELD (year, 2010, 2005, 2015)
# Сортировка по полю
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "actors",
"type": "select",
"sort": [
{
"field": "person",
"desc": false
}
]
}'
....
# Сортировка по вложенному полю.
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "actors",
"type": "select",
"sort": [
{
"field": "nested.nested2.nested3.nested4.newField",
"desc": false
}
]
}'
....
# Сортировка с использованием FIELD
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "media_items",
"type": "select",
"filters": [
{
"field": "ratings.imdb",
"cond": "GE",
"value": 9.2
}
],
"sort": [
{
"field": "year",
"values": [
2010,
2005,
2015
],
"desc": false
}
]
}'
Для индексов также возможно установить пользовательский порядок сортировки (подробнее — в разделе Параметры индексных полей ).
Пример:
type SortModeCustomItem struct {
ID int `reindex:"id,,pk"`
InsItem string `reindex:"item_custom,hash,collate_custom=a-zA-Z0-9"` // Для индекса задан пользовательский порядок сортировки
}
type SortModeCustomItem struct {
ID int `reindex:"id,,pk"`
InsItem string `reindex:"item_custom,hash,collate_custom=АаБбВвГгДдЕеЖжЗзИиКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭ-ЯAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0-9ЁёЙйэ-я"` // Для индекса задан пользовательский порядок сортировки
}
Сортировка с использованием функций rank(), abs(), ST_Distance()
rank()
обеспечивает сортировку по рангу соответствия результата поисковому запросу.
Используется только при полнотекстовом поиске.
Примеры:
query = db.Query("actors").Where("description", reindexer.EQ, "ququ").
Sort("rank() + id / 100", true)
SELECT * FROM actors WHERE description = 'ququ' ORDER BY 'rank() + id / 100' DESC
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "actors",
"type": "select",
"filters": [
{
"field": "description",
"cond": "EQ",
"value": "ququ"
}
],
"sort": [
{
"field": "rank() + id / 100",
"desc": true
}
]
}'
Функция abs()
возвращает модуль числа.
Примеры использования:
query = db.Query("actors").Where("description", reindexer.EQ, "ququ").
Sort("-id + Abs(-value + -1.2) * -Rank()", true)
SELECT * FROM actors WHERE description = 'ququ' ORDER BY '-id + Abs(-value + -1.2) * -Rank()' DESC
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "actors",
"type": "select",
"filters": [
{
"field": "description",
"cond": "EQ",
"value": "ququ"
}
],
"sort": [
{
"field": "-id + Abs(-value + -1.2) * -Rank()",
"desc": true
}
]
}'
ST_Distance()
используется для вычисления расстояния между двумя точками.
Точками могут быть rtree
индексы в основном или приджойненных неймспейсах либо фиксированные точки в формате ST_GeomFromText("point(1 -3)")
.
Пример:
query = db.Query("actors").
Join(db.Query("cities")).On("birth_place_id", reindexer.EQ, "id").
Sort("ST_Distance(cities.center, ST_GeomFromText(\"point(1 -3)\"))", false).
Sort("ST_Distance(location, cities.center)", false)
SELECT * FROM actors ORDER BY 'ST_Distance(location, ST_GeomFromText(\"point(1 -3)\"))' ASC ORDER BY 'ST_Distance(location, cities.center)' ASC
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "actors",
"type": "select",
"sort": [
{
"field": "ST_Distance(location, ST_GeomFromText(\"point(1 -3)\"))",
"desc": false
},
{
"field": "ST_Distance(location, cities.center)",
"desc": false
}
]
}'
Сортировка в соответствии с арифметическим выражением
Для установки правила сортировки могут использоваться арифметические выражения, включающие операции сложения (+
), вычитания (-
), умножения (*
), деления (/
) и скобки (()
).
Арифметические выражения в SQL-запросах указываются в одинарных кавычках.
Параметры и математические операторы в них должны быть разделены пробелом.
Поля, используемые в выражении, должны содержать числовые значения (
bool
,int
,int64
илиfloat
) либо строку, в которой записано число (ведущие и конечные пробелы игнорируются).
Примеры:
query = db.Query("actors").Sort("person.age / -10 + price / 1000 * (id - 5)", true)
SELECT * FROM actors WHERE description = 'ququ' ORDER BY 'rank() + id / 100' DESC
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "actors",
"type": "select",
"filters": [
{
"field": "description",
"cond": "EQ",
"value": "ququ"
}
],
"sort": [
{
"field": "rank() + id / 100",
"desc": true
}
]
}'
Форсированная сортировка
Вы можете указать конкретные значения, которые при сортировке будут выводиться первыми в результатах (при их наличии в неймспейсе).
Пример:
query := db.Query("items").Sort("id", false, "100", "11", "10")
SELECT * FROM test_namespace ORDER BY FIELD(id, '100', '10', '11')
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_namespace",
"type": "select",
"sort": [
{
"field": "id",
"values": [
"100",
"10",
"11"
]
}
]
}'
Форсированная сортировка применяется только для первого поля в ORDER BY. Запросы с несколькими полями в ORDER BY вида
SELECT * FROM test_namespace ORDER BY FIELD(id, '100', '10', '11'), FIELD(location_id, 200001, 600001, 400001)
иSELECT * FROM test_namespace ORDER BY id, FIELD(location_id, 200001, 600001, 400001)
не поддерживаются. Пример корректного запроса с форсированной сортировкой:SELECT * FROM test_namespace ORDER BY FIELD(id, '100', '10', '11'), location_id
.
Ограничение выдачи (LIMIT и OFFSET)
Для ограничения выдачи используется параметр LIMIT
.
Для вывода элементов, начиная с определенной позиции используется параметр OFFSET
.
Пример:
query := db.Query("test_table").
Where("year", reindexer.QE, 2022).
Limit(10)
....
query := db.Query("test_table").
Where("year", reindexer.QE, 2022).
Limit(10).
Offset(5).
Sort("price", false)
SELECT * FROM test_table WHERE year=2022 LIMIT 10
....
SELECT * FROM test_table WHERE year=2022 LIMIT 10 OFFSET 5 ORDER BY price
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_namespace",
"type": "select",
"limit": 10,
"filters": [
{
"field": "year",
"cond": "EQ",
"value": [
2022
]
}
]
}'
....
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_namespace",
"type": "select",
"limit": 10,
"offset": 5,
"filters": [
{
"field": "year",
"cond": "EQ",
"value": [
2022
]
}
],
"sort": [
{
"field": "price",
"desc": false
}
]
}'