Группировка и Агрегации
Archie Core предлагает мощные возможности группировки и агрегации через свой GraphQL API. Вы можете группировать записи по значениям полей, вычислять агрегатные функции (COUNT, SUM, AVG, MIN, MAX, COUNT_DISTINCT), фильтровать группы с помощью условий HAVING и сортировать результаты по агрегированным значениям.
Аргументы запроса
Заголовок раздела «Аргументы запроса»При использовании группировки и агрегации следующие аргументы доступны в любом запросе списка:
| Аргумент | Тип | Описание |
|---|---|---|
groupBy | [{TableName}GroupBy] | Поля для группировки результатов |
aggregateBy | [{TableName}AggregateInput] | Агрегатные функции для вычисления |
having | [{TableName}HavingFilterInput] | Фильтрация групп по результатам агрегации |
aggregateSort | [{TableName}AggregateSortInput] | Сортировка результатов по агрегированным значениям |
Эти аргументы можно комбинировать со стандартными аргументами, такими как filter, first, skip и orderBy.
GroupBy
Заголовок раздела «GroupBy»Аргумент groupBy принимает массив значений enum, представляющих поля для группировки. Значения enum следуют шаблону: имя поля в camelCase, преобразованное в ВЕРХНИЙ_РЕГИСТР.
Соглашение об именовании:
| Имя столбца (БД) | Имя поля (GraphQL) | Значение enum GroupBy |
|---|---|---|
payment_method | paymentMethod | PAYMENTMETHOD |
created_at | createdAt | CREATEDAT |
status | status | STATUS |
category_id | categoryId | CATEGORYID |
Пример: Группировка студентов по активному статусу
Заголовок раздела «Пример: Группировка студентов по активному статусу»Запрос
query { students(groupBy: [ISACTIVE]) { items { isActive } count }}Ответ
{ "data": { "students": { "items": [ { "isActive": true }, { "isActive": false } ], "count": 2 } }}AggregateBy
Заголовок раздела «AggregateBy»Аргумент aggregateBy позволяет вычислять агрегатные функции над сгруппированными (или несгруппированными) данными. Каждая агрегация требует function, опциональное field и обязательный alias.
Структура AggregateInput
Заголовок раздела «Структура AggregateInput»input {TableName}AggregateInput { function: AggregateFunction! field: {TableName}AggregateField alias: String!}Доступные агрегатные функции
Заголовок раздела «Доступные агрегатные функции»| Функция | Описание | Требуется field? |
|---|---|---|
COUNT | Подсчёт строк | Нет (использует COUNT(*) при опускании) |
SUM | Суммирование числовых значений | Да |
AVG | Вычисление среднего | Да |
MIN | Поиск минимального значения | Да |
MAX | Поиск максимального значения | Да |
COUNT_DISTINCT | Подсчёт уникальных значений | Да |
Enum field следует той же конвенции ВЕРХНЕГО_РЕГИСТРА, что и GroupBy.
alias — это строка, которую вы выбираете для именования результата. Она появляется как ключ в объекте ответа aggregates.
Пример: Подсчёт и средний возраст студентов, сгруппированных по активному статусу
Заголовок раздела «Пример: Подсчёт и средний возраст студентов, сгруппированных по активному статусу»Запрос
query { students( groupBy: [ISACTIVE] aggregateBy: [ { function: COUNT, alias: "totalStudents" } { function: AVG, field: AGE, alias: "avgAge" } ] ) { items { isActive } count aggregates }}Ответ
{ "data": { "students": { "items": [ { "isActive": true }, { "isActive": false } ], "count": 2, "aggregates": [ { "totalStudents": 5, "avgAge": 23.4 }, { "totalStudents": 2, "avgAge": 21.0 } ] } }}Каждая запись в массиве aggregates соответствует группе с тем же индексом в items.
Аргумент having фильтрует группы по результатам агрегации, эквивалентно предложению SQL HAVING. Использует специальный тип ввода с тремя полями.
Структура HavingFilterInput
Заголовок раздела «Структура HavingFilterInput»input {TableName}HavingFilterInput { alias: String! operator: HavingOperator! value: Float!}alias: Должен совпадать с псевдонимом, определённым вaggregateBy.operator: Оператор сравнения (см. таблицу ниже).value: Числовой порог для сравнения.
Доступные операторы
Заголовок раздела «Доступные операторы»| Оператор | Эквивалент SQL |
|---|---|
EQUALS | = |
NOT_EQUALS | != |
GREATER_THAN | > |
GREATER_THAN_OR_EQUAL | >= |
LESS_THAN | < |
LESS_THAN_OR_EQUAL | <= |
Пример: Города с более чем 3 студентами
Заголовок раздела «Пример: Города с более чем 3 студентами»Запрос
query { students( groupBy: [CITYID] aggregateBy: [ { function: COUNT, alias: "studentCount" } ] having: [ { alias: "studentCount", operator: GREATER_THAN, value: 3 } ] ) { items { cityId } count aggregates }}Ответ
{ "data": { "students": { "items": [ { "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" } ], "count": 1, "aggregates": [ { "studentCount": 5 } ] } }}Возвращаются только группы, удовлетворяющие условию агрегации.
AggregateSort
Заголовок раздела «AggregateSort»Аргумент aggregateSort сортирует сгруппированные результаты по агрегированному значению, а не по обычному полю.
Структура AggregateSortInput
Заголовок раздела «Структура AggregateSortInput»input {TableName}AggregateSortInput { alias: String! direction: SortDirection!}alias: Должен совпадать с псевдонимом, определённым вaggregateBy.direction:ASC(по возрастанию) илиDESC(по убыванию).
Пример: Топ-3 города по количеству студентов
Заголовок раздела «Пример: Топ-3 города по количеству студентов»Запрос
query { students( groupBy: [CITYID] aggregateBy: [ { function: COUNT, alias: "studentCount" } ] aggregateSort: [ { alias: "studentCount", direction: DESC } ] first: 3 ) { items { cityId } count aggregates }}Ответ
{ "data": { "students": { "items": [ { "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" }, { "cityId": "0174dc55-d494-4ebc-a0e9-13575461cad4" }, { "cityId": "a2b3c4d5-e6f7-8901-2345-678901234567" } ], "count": 3, "aggregates": [ { "studentCount": 5 }, { "studentCount": 3 }, { "studentCount": 2 } ] } }}Комбинирование всех функций
Заголовок раздела «Комбинирование всех функций»Вы можете комбинировать filter, groupBy, aggregateBy, having, aggregateSort и first в одном запросе для сложного анализа.
Пример: Топ-5 городов активных студентов со средним возрастом выше 20, отсортированные по среднему возрасту
Заголовок раздела «Пример: Топ-5 городов активных студентов со средним возрастом выше 20, отсортированные по среднему возрасту»Запрос
query { students( filter: { isActive: { equals: true } } groupBy: [CITYID] aggregateBy: [ { function: COUNT, alias: "studentCount" } { function: AVG, field: AGE, alias: "avgAge" } { function: MAX, field: AGE, alias: "maxAge" } ] having: [ { alias: "avgAge", operator: GREATER_THAN, value: 20 } ] aggregateSort: [ { alias: "avgAge", direction: DESC } ] first: 5 ) { items { cityId } count aggregates }}Ответ
{ "data": { "students": { "items": [ { "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" }, { "cityId": "0174dc55-d494-4ebc-a0e9-13575461cad4" } ], "count": 2, "aggregates": [ { "studentCount": 3, "avgAge": 24.3, "maxAge": 28 }, { "studentCount": 2, "avgAge": 22.5, "maxAge": 25 } ] } }}Этот запрос:
- Фильтрует только активных студентов (
filter). - Группирует по городу (
groupBy). - Вычисляет количество, средний возраст и максимальный возраст в каждой группе (
aggregateBy). - Сохраняет только группы со средним возрастом выше 20 (
having). - Сортирует по среднему возрасту по убыванию (
aggregateSort). - Ограничивает до топ-5 групп (
first).
Структура ответа
Заголовок раздела «Структура ответа»При использовании агрегации ответ следует стандартному типу Connection с дополнительным полем aggregates:
| Поле | Тип | Описание |
|---|---|---|
items | [{TableName}!]! | Сгруппированные записи (по одной на группу, с значениями сгруппированных полей) |
count | Int! | Количество возвращённых групп |
pageInfo | PageInfo! | Информация о пагинации (hasNextPage, hasPreviousPage) |
aggregates | JSON | Массив объектов, каждый содержит вычисленные агрегированные значения, индексированные по псевдониму |
Массив aggregates параллелен items — агрегат с индексом i соответствует группе с индексом i в items.
Важные замечания
Заголовок раздела «Важные замечания»- Значения enum GroupBy и AggregateField используют ВЕРХНИЙ_РЕГИСТР имени поля в camelCase:
payment_method→paymentMethod→PAYMENTMETHOD. - Псевдонимы having должны совпадать с псевдонимом, определённым в
aggregateBy. Если не совпадают, условие having игнорируется. - Псевдонимы aggregateSort должны совпадать с псевдонимом, определённым в
aggregateBy. - COUNT без field использует
COUNT(*), подсчитывая все строки в группе. - Несколько условий having можно комбинировать — все должны выполняться (логика AND).
- Несколько записей aggregateSort применяются в порядке приоритета (первая — основной порядок сортировки).
- Стандартные аргументы пагинации (
first,skip,after,before) работают со сгруппированными результатами. - Аргумент filter применяется до группировки (эквивалент SQL WHERE), а having — после группировки (эквивалент SQL HAVING).