---
title: GraphQL Aggregations
slug: graphql-aggregations
createdAt: 2026-06-13T01:56:04.473Z
---

# 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:

```graphql
query {
  aggregate__Product(
    where: { status: { _eq: "Active" } }
    groupBy: [productCategory]
  ) {
    productCategory
    count(field: id, distinct: true)
  }
}
```

```json
{
  "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:

```graphql
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:

```graphql
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:

```graphql
query {
  aggregate__Subscription {
    count_id: count(field: id, distinct: true)
    count_customerId: count(field: customerId, distinct: true)
  }
}
```

```json
{
  "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:

```graphql
# Array form
aggregate__Product(groupBy: [productCategory]) { ... }

# Scalar form (equivalent)
aggregate__Product(groupBy: productCategory) { ... }
```

You can group by up to **3 fields**:

```graphql
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:

```graphql
query {
  aggregate__Product(groupBy: [status]) {
    status
  }
}
```

Grouped results support pagination through the `page` argument. Request successive pages by advancing the `cursor`:

```graphql
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:

```graphql
query {
  aggregate__Invoice(groupBy: [currencyIsoCode]) {
    currencyIsoCode
    count(field: id, distinct: true)
    sum(field: amount)
  }
}
```

```json
{
  "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 GraphQL](docId:-9J6pCiGzvpCGzSDIkCwc) — endpoints, supported objects, filtering, pagination, and introspection.
- [GraphQL Relationship Traversal](docId\:vEMQp0s7GgC4wYRgYlgCp) — query nested and reverse relationships in a single round trip.
