GraphQL Aggregations
Introduction
Aggregations let you compute rollups — counts, sums, averages, minimums, maximums, and grouped breakdowns — directly in GraphQL, so you can answer analytical questions in a single round trip instead of exporting raw records and calculating externally.
Every object collection has an aggregate companion field named aggregate__<Object> (for example, aggregate__Product, aggregate__Invoice, aggregate__Subscription). The aggregate field accepts the same where and page arguments as the regular collection, plus a groupBy argument.
This enables one-round-trip questions such as:
- Number of active products by category
- Total pipeline value by stage and currency
- Invoice totals by status
Supported Functions
Within an aggregate__<Object> selection you can request any of the following:
- count(field: <field>, distinct: <bool>)
- sum(field: <field>)
- min(field: <field>)
- max(field: <field>)
- avg(field: <field>)
The example below counts active products grouped by category:
query {
aggregate__Product(
where: { status: { _eq: "Active" } }
groupBy: [productCategory]
) {
productCategory
count(field: id, distinct: true)
}
}{
"data": {
"result": {
"aggregate__Product": [
{ "productCategory": "Software", "count": 5 },
{ "productCategory": "Hardware", "count": 3 },
{ "productCategory": "Services", "count": 2 }
]
}
}
}You can combine multiple functions in one query. The following returns the count and total amount of invoices by status:
query {
aggregate__Invoice(groupBy: [status]) {
status
count(field: id, distinct: true)
sum(field: amount)
}
}When no groupBy is supplied, the aggregate returns a single summary row:
query {
aggregate__Subscription {
count(field: id, distinct: true)
sum(field: quantity)
min(field: quantity)
max(field: quantity)
avg(field: quantity)
}
}Aliased Functions
Use GraphQL field aliases to return more than one variant of the same function in a single query — for example, distinct counts of two different fields:
query {
aggregate__Subscription {
count_id: count(field: id, distinct: true)
count_customerId: count(field: customerId, distinct: true)
}
}{
"data": {
"result": {
"aggregate__Subscription": [
{ "count_id": 150, "count_customerId": 75 }
]
}
}
}Grouping with groupBy
The groupBy argument breaks results into one row per distinct combination of the grouped fields. It accepts either a single field or an array of fields — both forms are equivalent:
# Array form
aggregate__Product(groupBy: [productCategory]) { ... }
# Scalar form (equivalent)
aggregate__Product(groupBy: productCategory) { ... }You can group by up to 3 fields:
query {
aggregate__Product(
where: { status: { _eq: "Active" } }
groupBy: [productCategory, priceModel, billingPeriod]
) {
productCategory
priceModel
billingPeriod
count(field: id, distinct: true)
}
}A groupBy with no aggregate functions behaves like SELECT DISTINCT — it returns the distinct combinations of the grouped fields:
query {
aggregate__Product(groupBy: [status]) {
status
}
}Grouped results support pagination through the page argument. Request successive pages by advancing the cursor:
query {
aggregate__Product(
where: { status: { _eq: "Active" } }
groupBy: [productCategory]
page: { cursor: 0, limit: 2 }
) {
productCategory
count(field: id, distinct: true)
}
}Multi-Currency Aggregations
Currency amounts are never auto-converted across currencies. To aggregate monetary fields in a multi-currency org, group by currencyIsoCode so each currency is returned on its own row:
query {
aggregate__Invoice(groupBy: [currencyIsoCode]) {
currencyIsoCode
count(field: id, distinct: true)
sum(field: amount)
}
}{
"data": {
"result": {
"aggregate__Invoice": [
{ "currencyIsoCode": "USD", "count": 50, "sum": 10000.00 },
{ "currencyIsoCode": "EUR", "count": 30, "sum": 8000.00 }
]
}
}
}Validation Rules
Aggregate queries are validated before they run. The following are rejected with an error:
Query | Why it fails |
|---|---|
sum(field: name) | sum, avg, min, and max require a numeric field — they cannot be applied to text fields. |
count with no field argument | count requires a field argument (for example count(field: id, distinct: true)). |
groupBy with more than 3 fields | groupBy is capped at 3 fields. |
page: { limit: 1001 } | The aggregate page.limit cannot exceed 1000. |
Related Guides
- Query Nue Objects using GraphQLQuery Nue Objects using GraphQL — endpoints, supported objects, filtering, pagination, and introspection.
- GraphQL Relationship TraversalGraphQL Relationship Traversal — query nested and reverse relationships in a single round trip.