Сортировка и ограничение выдачи
Reindexer может сортировать документы по возрастанию (ASC, используется по умолчанию) и убыванию (DESC).
При задании условий сортировки возможно использование математических выражений.
Выражения с условиями сортировки могут содержать:
- имена полей и индексов неймспейсов;
- числа;
- функции
rank(),abs(),ST-Distance(); - функции
hash(),hash(seed)(Вычисляет хеш от внутреннего идентификатора записи. Еслиseedне задан, то он генерируется случайным для каждой выборки); - скобки и арифметические выражения.
Сортировка по полю
Выражения с условиями сортировки могут содержать имена полей и индексов неймспейсов (включая вложенные и поля приджойненных неймспейсов).
Сортировка по полям приджойненных неймспейсов работает только для
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)
# Сортировка по полю
query = db.new_query("actors").sort("id", False)
# Сортировка по вложенному полю
query = db.new_query("actors").sort("person.age", False)
# Сортировка по полю приджойненного неймспейса
query = (
db.new_query("actors")
.inner_join(db.new_query("cities"), "joined")
.on("birth_place_id", CondType.CondEq, "id")
.sort("cities.population", false)
)
// Сортировка по полю
ResultIterator<Item> iterator = db.query("actors", Item.class)
.sort("id", false);
// Сортировка по вложенному полю
ResultIterator<Item> iterator = db.query("actors", Item.class)
.sort("person.age", false);
// Сортировка по полю приджойненного неймспейса
Query<ItemWithJoin> query = db.query("actors", ItemWithJoin.class)
.innerJoin(db.query("cities", City.class)
.on("birth_place_id", Condition.EQ, "id"), "joinedItems")
.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ЁёЙйэ-я"` // Для индекса задан пользовательский порядок сортировки
}
sort_mode_custom_item = [
{
"name": "id",
"json_paths": ["id"],
"field_type": "int",
'is_pk': True
},
{
"name": "item_custom",
"json_paths": ["item_custom"],
"field_type": "string",
"collate_mode": "custom",
"sort_order_letters": "a-zA-Z0-9"
}
]
sort_mode_custom_item = [
{
"name": "id",
"json_paths": ["id"],
"field_type": "int",
'is_pk': True
},
{
"name": "item_custom",
"json_paths": ["item_custom"],
"field_type": "string",
"collate_mode": "custom",
"sort_order_letters": "АаБбВвГгДдЕеЖжЗзИиКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭ-ЯAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0-9ЁёЙйэ-я"
}
]
При задании пользовательского порядка сортировки возможно указание значений через интервалы.
В представленном выше примере интервал
Э-Явключает значения:Э,Ю,Я, а интервал0-9— включает цифры от0до9.
Сортировка с использованием функций rank(), abs(), ST_Distance()
rank() обеспечивает сортировку по рангу соответствия результата поисковому запросу.
Используется только при полнотекстовом поиске.
Примеры:
query = db.Query("actors").Where("description", reindexer.EQ, "test").
Sort("rank() + id / 100", true)
query = (
db.new_query("actors")
.where("description", CondType.CondEq, "test")
.sort("rank() + id / 100", True)
)
ResultIterator<Item> query = db.query("items", Item.class)
.where("description", Condition.EQ, "ququ")
.sort("rank() + id / 100", true);
SELECT * FROM actors WHERE description = 'test' 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": "test"
}
],
"sort": [
{
"field": "rank() + id / 100",
"desc": true
}
]
}'
Функция abs() возвращает модуль числа.
Примеры использования:
query = db.Query("actors").Where("description", reindexer.EQ, "test").
Sort("-id + Abs(-value + -1.2) * -Rank()", true)
query = (
db.new_query("actors")
.where("description", CondTypeƒ.CondEq, "test")
.sort("-id + abs(-value + -1.2) * -rank()", True)
)
ResultIterator<Item> query = db.query("items", Item.class)
.where("description", Condition.EQ, "ququ")
.sort("-id + Abs(-value + -1.2) * -Rank()", true);
SELECT * FROM actors WHERE description = 'test' 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": "test"
}
],
"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)
point = Point(1, -3)
req = f"ST_Distance(cities.center, ST_GeomFromText('point({point.x:.4f} {point.y:.4f})'))"
query = (
db.new_query("actors")
.join(db.new_query("cities"), "joined")
.on("birth_place_id", CondType.CondEq, "id")
.sort(req, False)
.sort("ST_Distance(location, cities.center)", False)
)
ResultIterator<Item> iterator = db.query("actors", Item.class)
.join(db.query("cities", Item.class)
.on("id", Condition.EQ, "id"), "joinedItems")
.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").Where("description", reindexer.EQ, "test").Sort("rank() + id / 100", true)
query = (
db.new_query("actors")
.where("description", CondType.CondEq, "test")
.sort("rank() + id / 100", True)
)
ResultIterator<Item> iterator = db.query("actors", Item.class)
.where("description", Condition.EQ, "ququ")
.sort("rank() + id / 100", true);
SELECT * FROM actors WHERE description = 'test' 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": "test"
}
],
"sort": [
{
"field": "rank() + id / 100",
"desc": true
}
]
}'
Форсированная сортировка
Вы можете указать конкретные значения, которые при сортировке будут выводиться первыми в результатах (при их наличии в неймспейсе).
Пример:
query := db.Query("items").Sort("id", false, "100", "11", "10")
query := db.new_query("items").sort("id", False, ["100", "11", "10"])
ResultIterator<Item> iterator = db.query("items", Item.class)
.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.EQ, 2022).
Limit(10)
query := db.Query("test_table").
Where("year", reindexer.EQ, 2022).
Limit(10).
Offset(5).
Sort("price", false)
query := (
db.new_query("test_table")
.where("year", CondType.CondEq, 2022)
.limit(10)
)
query := (
db.new_query("test_table")
.where("year", CondType.CondEq, 2022)
.limit(10)
.offset(5)
.sort("price", False)
)
ResultIterator<Item> query = db.query("test_table", Item.class)
.where("year", Condition.EQ, 2022)
.limit(10);
ResultIterator<Item> query = db.query("test_table", Item.class)
.where("year", Condition.EQ, 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
}
]
}'