jq · lesson 19 of 32 · Aggregation

reduce & foreach

reduce stream as $x (start; update) folds a stream into a single value. foreach is the same, but emits the state after every step.

Examples

Example 1Count members per role

Document

{
  "team": "Platform",
  "office": { "city": "Berlin", "floor": 3 },
  "members": [
    { "name": "Ada", "age": 36, "role": "lead", "active": true,
      "email": "[email protected]", "skills": ["rust", "sql"] },
    { "name": "Linus", "age": 28, "role": "dev", "active": true,
      "email": null, "skills": ["c", "shell"] },
    { "name": "Grace", "age": 45, "role": "dev", "active": false,
      "skills": ["cobol"] },
    { "name": "Alan", "age": 41, "role": "qa", "active": true,
      "email": "[email protected]", "skills": [] }
  ]
}

Query

reduce .members[] as $m ({}; .[$m.role] += 1)
  1. reduce .members[] as $m Loop over the stream, binding each element to $m.
  2. {} The starting value: an empty object.
  3. .[$m.role] += 1 Each round: bump the counter stored under this member's role (a missing key counts as 0).

Result

{"lead":1,"dev":2,"qa":1}

Try it in the playground

Example 2A running total of ages

Document

{
  "team": "Platform",
  "office": { "city": "Berlin", "floor": 3 },
  "members": [
    { "name": "Ada", "age": 36, "role": "lead", "active": true,
      "email": "[email protected]", "skills": ["rust", "sql"] },
    { "name": "Linus", "age": 28, "role": "dev", "active": true,
      "email": null, "skills": ["c", "shell"] },
    { "name": "Grace", "age": 45, "role": "dev", "active": false,
      "skills": ["cobol"] },
    { "name": "Alan", "age": 41, "role": "qa", "active": true,
      "email": "[email protected]", "skills": [] }
  ]
}

Query

[foreach (.members[] | .age) as $a (0; . + $a)]
  1. foreach Like reduce, but outputs the state after every step instead of only the last.
  2. (.members[] | .age) as $a The stream to loop over, and the variable holding each item.
  3. 0 The starting state.
  4. ; . + $a The update: new state = old state (.) plus this age.

Result

[36,64,109,150]

Try it in the playground

Good to know

  • Inside the update expression, . is the accumulated state — not the input you started with.

About jsonquery

Query, format and learn JSON with jq, JSONPath, JMESPath and JSON Pointer. It is the engine of the desktop app, run in your browser.

Engine
The desktop app’s, compiled to WebAssembly
Licence
MIT (the engine and the app)
Source
GitHub
Contact
The contact form (private)
Public issues
GitHub
Legal
Privacy policy

Known limitations: a file over 10 MB opens read-only and one over 512 MB does not open here; the desktop app has no such limit.