# Aggregate

Group records by a JSONPath key and reduce each group to one record.

## When to use it

Use this for a compact total per group. Choose a grouping path, then count records, sum numeric values, concatenate text, or collect values. Non-numeric values do not contribute to a numeric sum; inspect the sample output when input types vary.

## Add and configure

1. Add **Aggregate** from the workflow step picker.
2. Give the step a recognisable name and connect its required inputs.
3. Set the options below. Nested names identify fields within an object or a list item.
4. Validate the recipe, inspect the test result, then run it on the intended data.

The step identifier used in the editor’s code view is `aggregate`.

## Settings

| Setting | Accepted value | Required | Default | What it controls |
| --- | --- | --- | --- | --- |
| Group By (`group_by`) | string | Yes | Not specified | JSONPath whose value becomes the group key. |
| Reduce (`reduce`) | "count" / "sum" / "concat" / "list" | No | "count" | Reduction applied to the group's values. |
| Separator (`separator`) | string | No | "\n" | Separator string for 'concat'. |
| Value (`value`) | string or null | No | null | JSONPath of the value to reduce (ignored for 'count'). |

## Inputs and outputs

| Direction | Port | Content | Required | Multiple records |
| --- | --- | --- | --- | --- |
| Inputs | `in` | records | Yes | Yes |
| Outputs | `out` | records | Yes | Yes |

## Effects, testing, and recovery

Transforms or passes records without a declared external side effect.

The declared preview behaviour is to execute this step. Reads, processing, or model usage can therefore be real. Read [dry runs](/docs/workflows/dry-runs) before using a preview with live connections.

No duplicate-prevention key is declared for this step. The step declares safe replay for its supported recovery path.

## Example: Count records per status

Step settings:

```json
{
  "group_by": "$.status"
}
```

Input records:

```json
[
  {
    "status": "open"
  },
  {
    "status": "open"
  },
  {
    "status": "closed"
  }
]
```

Expected output for this example:

```json
[
  {
    "count": 2,
    "group": "open"
  },
  {
    "count": 1,
    "group": "closed"
  }
]
```

## Example: Sum amounts per customer (non-numeric values are skipped)

Step settings:

```json
{
  "group_by": "$.customer",
  "reduce": "sum",
  "value": "$.amount"
}
```

Input records:

```json
[
  {
    "amount": 10,
    "customer": "acme"
  },
  {
    "amount": "2.5",
    "customer": "acme"
  },
  {
    "amount": 4,
    "customer": "globex"
  },
  {
    "amount": "n/a",
    "customer": "globex"
  }
]
```

Expected output for this example:

```json
[
  {
    "group": "acme",
    "sum": 12.5
  },
  {
    "group": "globex",
    "sum": 4.0
  }
]
```

## Example: Concatenate titles per author

Step settings:

```json
{
  "group_by": "$.author",
  "reduce": "concat",
  "separator": ", ",
  "value": "$.title"
}
```

Input records:

```json
[
  {
    "author": "ada",
    "title": "Notes"
  },
  {
    "author": "ada",
    "title": "Engine"
  }
]
```

Expected output for this example:

```json
[
  {
    "group": "ada",
    "text": "Notes, Engine"
  }
]
```

## Check the result

Inspect the selected run’s status, counts, errors, and output records. An empty collection can be a valid result, and a completed step can contain per-record failures where the step defines that behaviour. Check the next step’s expected record shape before publishing or delivering the result.
