Pular para o conteúdo

Agrupamento e Agregações

O Archie Core oferece capacidades poderosas de agrupamento e agregação através da sua API GraphQL. Você pode agrupar registros por valores de campos, calcular funções de agregação (COUNT, SUM, AVG, MIN, MAX, COUNT_DISTINCT), filtrar grupos com condições HAVING e ordenar resultados por valores agregados.

Ao usar agrupamento e agregações, os seguintes argumentos estão disponíveis em qualquer query de lista:

ArgumentoTipoDescrição
groupBy[{TableName}GroupBy]Campos para agrupar resultados
aggregateBy[{TableName}AggregateInput]Funções de agregação a calcular
having[{TableName}HavingFilterInput]Filtrar grupos por resultados agregados
aggregateSort[{TableName}AggregateSortInput]Ordenar resultados por valores agregados

Estes argumentos podem ser combinados com argumentos padrão como filter, first, skip e orderBy.

O argumento groupBy aceita um array de valores enum que representam os campos a agrupar. Os valores enum seguem o padrão: o nome do campo em camelCase convertido em MAIÚSCULAS.

Convenção de nomenclatura:

Nome da coluna (DB)Nome do campo (GraphQL)Valor enum GroupBy
payment_methodpaymentMethodPAYMENTMETHOD
created_atcreatedAtCREATEDAT
statusstatusSTATUS
category_idcategoryIdCATEGORYID

Requisição

query {
students(groupBy: [ISACTIVE]) {
items {
isActive
}
count
}
}

Resposta

{
"data": {
"students": {
"items": [
{ "isActive": true },
{ "isActive": false }
],
"count": 2
}
}
}

O argumento aggregateBy permite calcular funções de agregação sobre dados agrupados (ou não). Cada agregado requer uma function, um field opcional e um alias obrigatório.

input {TableName}AggregateInput {
function: AggregateFunction!
field: {TableName}AggregateField
alias: String!
}
FunçãoDescriçãofield obrigatório?
COUNTContar linhasNão (usa COUNT(*) quando omitido)
SUMSomar valores numéricosSim
AVGCalcular médiaSim
MINEncontrar valor mínimoSim
MAXEncontrar valor máximoSim
COUNT_DISTINCTContar valores distintosSim

O enum field segue a mesma convenção MAIÚSCULAS que GroupBy.

O alias é uma string que você escolhe para nomear o resultado. Aparece como chave no objeto de resposta aggregates.

Exemplo: Contar e calcular média de idade de estudantes agrupados por estado ativo

Seção intitulada “Exemplo: Contar e calcular média de idade de estudantes agrupados por estado ativo”

Requisição

query {
students(
groupBy: [ISACTIVE]
aggregateBy: [
{ function: COUNT, alias: "totalStudents" }
{ function: AVG, field: AGE, alias: "avgAge" }
]
) {
items {
isActive
}
count
aggregates
}
}

Resposta

{
"data": {
"students": {
"items": [
{ "isActive": true },
{ "isActive": false }
],
"count": 2,
"aggregates": [
{ "totalStudents": 5, "avgAge": 23.4 },
{ "totalStudents": 2, "avgAge": 21.0 }
]
}
}
}

Cada entrada no array aggregates corresponde ao grupo no mesmo índice em items.

O argumento having filtra grupos com base em resultados agregados, equivalente à cláusula SQL HAVING. Utiliza um tipo de entrada dedicado com três campos.

input {TableName}HavingFilterInput {
alias: String!
operator: HavingOperator!
value: Float!
}
  • alias: Deve corresponder a um alias definido em aggregateBy.
  • operator: O operador de comparação (ver tabela abaixo).
  • value: O limiar numérico a comparar.
OperadorEquivalente SQL
EQUALS=
NOT_EQUALS!=
GREATER_THAN>
GREATER_THAN_OR_EQUAL>=
LESS_THAN<
LESS_THAN_OR_EQUAL<=

Requisição

query {
students(
groupBy: [CITYID]
aggregateBy: [
{ function: COUNT, alias: "studentCount" }
]
having: [
{ alias: "studentCount", operator: GREATER_THAN, value: 3 }
]
) {
items {
cityId
}
count
aggregates
}
}

Resposta

{
"data": {
"students": {
"items": [
{ "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" }
],
"count": 1,
"aggregates": [
{ "studentCount": 5 }
]
}
}
}

Apenas grupos que satisfazem a condição de agregação são retornados.

O argumento aggregateSort ordena os resultados agrupados por um valor agregado, em vez de por um campo regular.

input {TableName}AggregateSortInput {
alias: String!
direction: SortDirection!
}
  • alias: Deve corresponder a um alias definido em aggregateBy.
  • direction: ASC (ascendente) ou DESC (descendente).

Requisição

query {
students(
groupBy: [CITYID]
aggregateBy: [
{ function: COUNT, alias: "studentCount" }
]
aggregateSort: [
{ alias: "studentCount", direction: DESC }
]
first: 3
) {
items {
cityId
}
count
aggregates
}
}

Resposta

{
"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 }
]
}
}
}

Você pode combinar filter, groupBy, aggregateBy, having, aggregateSort e first em uma única query para análises complexas.

Exemplo: Top 5 cidades de estudantes ativos com idade média acima de 20, ordenadas por idade média

Seção intitulada “Exemplo: Top 5 cidades de estudantes ativos com idade média acima de 20, ordenadas por idade média”

Requisição

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
}
}

Resposta

{
"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 }
]
}
}
}

Esta query:

  1. Filtra apenas estudantes ativos (filter).
  2. Agrupa por cidade (groupBy).
  3. Calcula contagem, idade média e idade máxima para cada grupo (aggregateBy).
  4. Mantém apenas grupos com idade média acima de 20 (having).
  5. Ordena por idade média descendente (aggregateSort).
  6. Limita aos 5 primeiros grupos (first).

Ao usar agregações, a resposta segue o tipo Connection padrão com um campo adicional aggregates:

CampoTipoDescrição
items[{TableName}!]!Os registros agrupados (um por grupo, contendo os valores dos campos agrupados)
countInt!Número de grupos retornados
pageInfoPageInfo!Info de paginação (hasNextPage, hasPreviousPage)
aggregatesJSONArray de objetos, cada um contendo os valores agregados calculados indexados por alias

O array aggregates é paralelo a items — o agregado no índice i corresponde ao grupo no índice i em items.

  • Os valores enum GroupBy e AggregateField usam MAIÚSCULAS do nome do campo em camelCase: payment_methodpaymentMethodPAYMENTMETHOD.
  • Os alias having devem corresponder a um alias definido em aggregateBy. Se não corresponder, a condição having é ignorada.
  • Os alias aggregateSort devem corresponder a um alias definido em aggregateBy.
  • COUNT sem field usa COUNT(*), contando todas as linhas no grupo.
  • Múltiplas condições having podem ser combinadas — todas devem ser satisfeitas (lógica AND).
  • Múltiplas entradas aggregateSort são aplicadas por ordem de prioridade (a primeira é a ordenação principal).
  • Os argumentos de paginação padrão (first, skip, after, before) funcionam com resultados agrupados.
  • O argumento filter é aplicado antes do agrupamento (equivalente a SQL WHERE), enquanto having é aplicado após o agrupamento (equivalente a SQL HAVING).