jq · lesson 22 of 32 · Tables & lookups

Records to a table

Most data is an array of objects. List the columns once, in a variable, and use that one list for the header and for every row: .[$cols[]] reads the listed fields in order.

Examples

Example 1Header and rows from one list of columns

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

["name", "role", "age"] as $cols | $cols, (.members[] | [.[$cols[]]]) | @csv
  1. ["name", "role", "age"] as $cols The columns you want, in the order you want them, saved as $cols.
  2. $cols The header row: the column names themselves.
  3. (.members[] | [.[$cols[]]]) One row per member. .[$cols[]] looks up each listed field in turn, and [ … ] collects the values into an array.
  4. @csv Writes the header and every row as CSV.

Result

"name","role","age"
"Ada","lead",36
"Linus","dev",28
"Grace","dev",45
"Alan","qa",41

Try it in the playground

Example 2A list in one cell

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

.members[] | [.name, (.skills | join(";"))] | @csv
  1. .members[] Each member in turn.
  2. (.skills | join(";")) A list can't sit in a cell as it is: join(";") glues its items into one string. An empty list becomes an empty string.
  3. @csv Writes the row.

Result

"Ada","rust;sql"
"Linus","c;shell"
"Grace","cobol"
"Alan",""

Try it in the playground

Example 3An object as two columns

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

.office | to_entries[] | [.key, .value] | @csv
  1. .office An object with two fields, city and floor.
  2. to_entries[] One {key, value} entry per field.
  3. [.key, .value] A two-cell row: the field's name, then its value.
  4. @csv Writes each row.

Result

"city","Berlin"
"floor",3

Try it in the playground

Good to know

  • keys_unsorted lists a record's keys in the order of the file, so (.members[0] | keys_unsorted) as $cols | … takes the columns from the first record. Every field must then be a string, number, boolean or null.
  • A field a record doesn't have reads as null, which is an empty cell.

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.