This jq cheat sheet lists the filters you use most, each run against one sample file with its real output. jq is a command-line JSON processor: you give it a filter and it reads JSON, transforms it and prints the result.
Every example was run with jq 1.8. Paste the sample and any filter into the jq tester to try them in your browser.
The sample file
All examples use this file, users.json:
{
"users": [
{ "id": 1, "name": "Ada", "email": "ada@example.com", "role": "admin", "active": true, "tags": ["math", "engines"] },
{ "id": 2, "name": "Grace", "email": "grace@example.com", "role": "editor", "active": false, "tags": ["cobol"] },
{ "id": 3, "name": "Linus", "email": "linus@example.com", "role": "editor", "active": true, "tags": [] }
]
}On the command line the pattern is jq 'FILTER' users.json. Quote the filter with single quotes so the shell leaves it alone.
Basic paths
| Filter | Result |
|---|---|
. | The whole document, pretty-printed |
.users[0].name | "Ada" |
.users[-1].email | "linus@example.com" |
.users[].name | "Ada", "Grace", "Linus" as three separate outputs |
.users[1:] | The last two users |
.users | length | 3 |
.users[0] | keys | ["active","email","id","name","role","tags"] (sorted) |
.users[0].missing | null, not an error |
.users[0].nickname // "none" | "none", the alternative operator fills in a default |
.[] iterates: it outputs each element of an array (or each value of an object) as its own result. The pipe | sends every result into the next filter, like a shell pipe.
Filter with select
select(condition) keeps a value when the condition is true and drops it otherwise.
| Filter | Result |
|---|---|
.users[] | select(.active) | .name | "Ada", "Linus" |
.users[] | select(.role == "editor" and .active) | .name | "Linus" |
.users[] | select(.id == 2) | .email | "grace@example.com" |
.users[] | select(.email | test("^g")) | .name | "Grace" (regular expression) |
.users[] | select(.tags | index("cobol")) | .name | "Grace" |
.users | map(select(.tags | length > 0)) | length | 2 |
.users | any(.role == "admin") | true |
.users | all(.active) | false |
Reshape with map and object construction
| Filter | Result |
|---|---|
.users | map(.email) | ["ada@example.com","grace@example.com","linus@example.com"] |
.users | map({name, role}) | [{"name":"Ada","role":"admin"}, ...] |
{count: (.users | length), names: [.users[].name]} | {"count":3,"names":["Ada","Grace","Linus"]} |
.users[] | {name, upper: (.name | ascii_upcase)} | {"name":"Ada","upper":"ADA"} and so on |
[.users[].tags[]] | ["math","engines","cobol"] |
del(.users[].email) | The document without any email fields |
.users[0] | with_entries(select(.key != "tags")) | Ada's object without tags |
.users | map({(.name): .id}) | add | {"Ada":1,"Grace":2,"Linus":3} |
{name} is short for {name: .name}. Parentheses around a key, as in {(.name): .id}, use a computed value as the key.
Sort, group and aggregate
| Filter | Result |
|---|---|
.users | sort_by(.name) | map(.name) | ["Ada","Grace","Linus"] |
.users | map(.name) | sort | reverse | ["Linus","Grace","Ada"] |
.users | map(.role) | unique | ["admin","editor"] |
.users | group_by(.role) | map({role: .[0].role, count: length}) | [{"role":"admin","count":1},{"role":"editor","count":2}] |
.users | map(.id) | add | 6 |
.users | max_by(.id) | .name | "Linus" |
reduce .users[] as $u (0; . + $u.id) | 6, the same sum with reduce |
Strings and output formats
| Filter | Result |
|---|---|
.users[] | "\(.name) <\(.email)>" | Ada <ada@example.com> and so on (string interpolation) |
.users[] | .tags | join(", ") | "math, engines", "cobol", "" |
.users[] | [.id, .name, .role] | @csv | 1,"Ada","admin" (with -r) |
.users[] | [.id, .name] | @tsv | Tab-separated rows (with -r) |
.users[0].name | @base64 | "QWRh" |
.users | map(.id) | @json | "[1,2,3]", JSON as a string |
"42" | tonumber | 42 |
@csv and @tsv need an array as input. Use them with the -r flag so the rows print as plain text instead of quoted JSON strings.
Update values
| Filter | Result |
|---|---|
.users[0].name |= ascii_upcase | Ada's name becomes "ADA" |
.users[] |= (.active = true) | Every user becomes active |
(.users[] | select(.id == 2) | .role) = "admin" | Grace's role becomes "admin" |
if .users[0].active then "yes" else "no" end | "yes" |
= sets a value. |= updates a value with a filter that receives the old value. Both return the whole document with the change applied.
Command-line flags
| Flag | What it does |
|---|---|
-r | Raw output: print strings without quotes |
-c | Compact output: one result per line |
-s | Slurp: read every input value into one array first |
-S | Sort the keys of every object in the output |
-n | Null input: start with null and read input with input or inputs |
-e | Set the exit status from the last output, useful in scripts |
--arg name value | Pass a string, used as $name in the filter |
--argjson name value | Pass a JSON value, such as a number |
# Emails of active users, one per line
jq -r '.users[] | select(.active) | .email' users.json
# Pass a value from the shell
jq --arg role editor '.users[] | select(.role == $role) | .name' users.json
# Count objects in a JSON Lines file
jq -s 'length' events.jsonlThe jq tester has toggles for -r, -c, -s and -S.
jq vs JSONPath
JSONPath only selects values. jq selects, filters, reshapes and computes, so anything that changes the output shape, such as counting, renaming or grouping, needs jq. The JSONPath cheat sheet has a side-by-side table of the same queries in both languages.
jqjq TesterRun any filter from this page against your own JSON.→