Skip to content
Terug naar blog
Tutorials

jq spiekbriefje: 30 praktische patronen voor JSON op de commandoregel

Beheers jq met 30 beproefde patronen voor filteren, transformeren en extraheren van JSON op de commandoregel — van kubectl en AWS tot logbestanden.

12 min leestijd

jq spiekbriefje: 30 praktische patronen voor JSON op de commandoregel

Je geeft kubectl get pods -o json door aan less, en de terminal bevriest op een muur van twee megabyte JSON. Je wil alleen de naam van elke pod met de fase Running. jq doet dat in drie tekens filtersyntaxis — als je de vocabulaire kent.

Dit is geen syntaxisreferentie. Het zijn 30 patronen die je daadwerkelijk typt, gegroepeerd op de taak die je probeert uit te voeren: toegang, filteren, transformeren, aggregeren, formatteren en samenvoegen met echte tools als kubectl, aws en docker.

Wanneer gebruik je jq, een browser-formatter of code?

jq is niet altijd het juiste antwoord. De drie eerlijke keuzes zien er zo uit:

SituatieBeste toolWaarom
Eén API-response, syntaxismarkering en regelnummers bij fouten nodigBrowser JSON FormatterVisueel overzicht, geen setup, privé in de browser
Shell-pipeline, logverwerking, CI-script, externe serverjqSamen te stellen, te scripten, geen GUI-afhankelijkheid
Bedrijfslogica, unit-tests, complexe vertakkingenTaalcode (JS / Python)Echte debugger, typen, bibliotheken

Kies jq wanneer de taak in een shell-pipeline past — alles anders is waarschijnlijk ergens anders gemakkelijker.

Installatie en je eerste pipeline

jq wordt geleverd als één binary op elk groot platform:

# macOS
brew install jq

# Debian / Ubuntu
sudo apt install jq

# Windows (winget)
winget install jqlang.jq

Een eerste pipeline, met de identiteitsfilter:

curl -s https://api.github.com/users/octocat | jq .

De .-filter neemt de invoer en geeft die ongewijzigd, netjes opgemaakt terug. Dat alleen al vervangt de meeste “even dit JSON-bestand openen in een editor”-momenten.

Vijf vlaggen dekken 90% van het dagelijkse gebruik:

VlagDoel
-rRuwe uitvoer — verwijder aanhalingstekens rondom string-resultaten
-cCompact — één JSON-waarde per regel (NDJSON)
-sSlurp — lees alle invoer in één array
-RRuwe invoer — lees regels als strings in plaats van JSON
-nNull-invoer — lees geen stdin, gebruik null als invoer

Het kernmodel: filters en pipes

Een filter neemt één JSON-waarde als invoer en produceert nul of meer JSON-waarden als uitvoer. Filters combineer je met een pipe |, die elke uitvoer van de linker filter doorgeeft als invoer aan de rechter filter. Dit is hetzelfde model als shell-pipes, maar dan met JSON-waarden die stromen in plaats van bytes.

# . — identiteit
echo '{"name":"Alice"}' | jq '.'

# .key — veldtoegang
echo '{"name":"Alice"}' | jq '.name'

# .key.sub — diep pad
echo '{"user":{"email":"a@x.com"}}' | jq '.user.email'

# .[] — itereer over array-elementen (produceert meerdere uitvoerwaarden)
echo '[{"id":1},{"id":2}]' | jq '.[] | .id'

# Pipe-samenstelling: elke uitvoer van .items[] wordt doorgegeven aan .name
echo '{"items":[{"name":"a"},{"name":"b"}]}' | jq '.items[] | .name'

Dat is de volledige grammatica. De 30 patronen hieronder zijn combinaties van deze bouwblokken.

30 patronen die je daadwerkelijk gebruikt

Elk patroon toont invoer-JSON, de opdracht en de uitvoer. Kopieer een patroon naar je terminal.

Toegang en extractie (patronen 1–5)

Patroon 1 — Veilige toegang met ?

Toegang tot een veld dat mogelijk niet bestaat, zonder foutmelding:

echo '{"name":"Alice"}' | jq '.address?.city?'
# Output: null

De ? onderdrukt fouten bij ontbrekende sleutels. Zonder ? geeft .address.city een typefout als .address ontbreekt.

Patroon 2 — Toegang via diep pad

echo '{"user":{"profile":{"email":"a@x.com"}}}' | jq '.user.profile.email'
# Output: "a@x.com"

Patroon 3 — Array-slicing

echo '[10,20,30,40,50]' | jq '.[1:3]'
# Output: [20, 30]

echo '[10,20,30,40,50]' | jq '.[-1]'
# Output: 50

Negatieve indices tellen van achteren. Slices gebruiken half-open intervallen, net als Python.

Patroon 4 — Recursieve afdaling om elke overeenkomende sleutel te vinden

echo '{"a":{"name":"x"},"b":[{"name":"y"},{"id":1}]}' | jq '.. | .name? | select(. != null)'
# Output: "x"
#         "y"

.. doorloopt elke waarde in de boom. Gecombineerd met .name? en select extraheert het elk name-veld ongeacht de diepte — onmisbaar bij het verkennen van onbekende JSON-schema’s.

Patroon 5 — Alle sleutels van een object opvragen

echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys'
# Output: ["apple", "mango", "zebra"]

echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys_unsorted'
# Output: ["zebra", "apple", "mango"]

keys sorteert alfabetisch; keys_unsorted bewaart de invoegvolgorde.

Filteren (patronen 6–10)

Patroon 6 — Een array filteren op voorwaarde

echo '[{"age":20},{"age":30},{"age":40}]' | jq 'map(select(.age > 25))'
# Output: [{"age":30},{"age":40}]

map(f) past f toe op elk element; select(cond) behoudt alleen elementen waarvoor de voorwaarde geldt.

Patroon 7 — Prefix-matching op strings

echo '[{"name":"api-gateway"},{"name":"web-ui"},{"name":"api-auth"}]' \
  | jq '.[] | select(.name | startswith("api"))'
# Output: {"name":"api-gateway"}
#         {"name":"api-auth"}

Ook handig: endswith("..."), contains("..."), test("^regex$").

Patroon 8 — Gecombineerde voorwaarden

echo '[{"type":"A","count":5},{"type":"A","count":15},{"type":"B","count":20}]' \
  | jq '.[] | select(.type == "A" and .count > 10)'
# Output: {"type":"A","count":15}

and, or, not werken zoals je verwacht.

Patroon 9 — Gevoelige velden verwijderen

echo '{"user":"alice","password":"s3cret","token":"abc"}' | jq 'del(.password, .token)'
# Output: {"user":"alice"}

del() accepteert meerdere paden en werkt veilig als een pad ontbreekt.

Patroon 10 — Dedupliceren op veld

echo '[{"id":1,"v":"a"},{"id":2,"v":"b"},{"id":1,"v":"a2"}]' | jq 'unique_by(.id)'
# Output: [{"id":1,"v":"a"},{"id":2,"v":"b"}]

unique dedupliceert hele waarden; unique_by(f) dedupliceert op het resultaat van een filter.

Transformeren (patronen 11–15)

Patroon 11 — Velden hernoemen

echo '[{"first_name":"Alice","age":30}]' | jq 'map({name: .first_name, age})'
# Output: [{"name":"Alice","age":30}]

De afkorting {age} is gelijk aan {age: .age}.

Patroon 12 — Een berekend veld toevoegen met string-interpolatie

echo '[{"first":"Alice","last":"Chen"}]' \
  | jq 'map(. + {fullName: "\(.first) \(.last)"})'
# Output: [{"first":"Alice","last":"Chen","fullName":"Alice Chen"}]

\(expr) evalueert expr en voegt de waarde in de string in.

Patroon 13 — Geneste arrays afvlakken

echo '[{"tags":["a","b"]},{"tags":["c"]}]' | jq '[.[] | .tags[]]'
# Output: ["a","b","c"]

echo '[[1,2],[3,[4,5]]]' | jq 'flatten'
# Output: [1,2,3,4,5]

flatten accepteert een optioneel diepte-argument: flatten(1) verwijdert slechts één niveau.

Patroon 14 — Object naar array en terug

echo '{"a":1,"b":2}' | jq 'to_entries'
# Output: [{"key":"a","value":1},{"key":"b","value":2}]

echo '[{"key":"a","value":1},{"key":"b","value":2}]' | jq 'from_entries'
# Output: {"a":1,"b":2}

Dit paar maakt transformaties mogelijk waarbij je over objectsleutels itereert — iets wat je met puntpadsyntaxis niet direct kunt.

Patroon 15 — Twee objecten diep samenvoegen

echo '{"a":{"x":1},"b":2}' | jq '. * {a:{y:9}, c:3}'
# Output: {"a":{"x":1,"y":9},"b":2,"c":3}

De *-operator voegt diep samen. Voor een oppervlakkige samenvoeging gebruik je + (rechter kant wint).

Aggregeren (patronen 16–20)

Patroon 16 — Lengte van arrays, objecten en strings

echo '[1,2,3,4]' | jq 'length'      # 4
echo '{"a":1,"b":2}' | jq 'length'  # 2
echo '"hello"' | jq 'length'        # 5

Patroon 17 — Een veld optellen

echo '[{"price":10},{"price":25},{"price":5}]' | jq '[.[].price] | add'
# Output: 40

add telt getallen op, voegt strings samen of arrays bijeen — afhankelijk van het invoertype.

Patroon 18 — Groeperen op veld

echo '[{"cat":"A","n":1},{"cat":"B","n":2},{"cat":"A","n":3}]' | jq 'group_by(.cat)'
# Output: [[{"cat":"A","n":1},{"cat":"A","n":3}],[{"cat":"B","n":2}]]

Elke groep wordt een binnenste array. Combineer met map om per groep te aggregeren.

Patroon 19 — Aflopend sorteren

echo '[{"date":"2026-01-03"},{"date":"2026-01-01"},{"date":"2026-01-02"}]' \
  | jq 'sort_by(.date) | reverse'
# Output: [{"date":"2026-01-03"},{"date":"2026-01-02"},{"date":"2026-01-01"}]

ISO 8601-datumstrings sorteren correct als strings. Voor andere formaten moet je ze eerst verwerken — de Unix-timestamp-gids behandelt epoch-seconden, milliseconden en tijdzoneconversie uitgebreid.

Patroon 20 — Maximum of minimum op veld

echo '[{"name":"a","rating":4.1},{"name":"b","rating":4.8},{"name":"c","rating":3.9}]' \
  | jq 'max_by(.rating)'
# Output: {"name":"b","rating":4.8}

min_by en max_by geven één element terug. Voor de top N gebruik je sort_by(.rating) | reverse | .[:N].

Uitvoer formatteren (patronen 21–25)

Patroon 21 — CSV-uitvoer

echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
  | jq -r '.[] | [.name, .age] | @csv'
# Output: "Alice",30
#         "Bob",25

@csv plaatst aanhalingstekens om strings en escapet aanhalingstekens erin. -r verwijdert de buitenste JSON-aanhalingstekens zodat de CSV direct doorgestuurd kan worden. Voor de volledige round-trip tussen CSV en JSON in pipelines, zie de CSV naar JSON-conversiegids.

Patroon 22 — TSV-uitvoer

echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' \
  | jq -r '.[] | [.id, .name] | @tsv'
# Output: 1	Alice
#         2	Bob

Tab-gescheiden uitvoer werkt goed met cut, awk en column -t.

Patroon 23 — Ruwe string-uitvoer

echo '["alpha","beta"]' | jq -r '.[]'
# Output: alpha
#         beta

Zonder -r zou elke regel aanhalingstekens hebben. Ruwe uitvoer is wat je doorgeeft aan xargs, while read of een andere shell-opdracht.

Patroon 24 — NDJSON / JSON Lines

echo '[{"a":1},{"a":2}]' | jq -c '.[]'
# Output: {"a":1}
#         {"a":2}

Elke regel is een zelfstandige JSON-waarde — het formaat dat Kafka, Elasticsearch en de meeste gestructureerde loggers gebruiken. -c verwijdert ook alle interne witruimte.

Patroon 25 — String-interpolatie voor opgemaakte uitvoer

echo '[{"name":"server-1","cpu":0.73},{"name":"server-2","cpu":0.21}]' \
  | jq -r '.[] | "\(.name): \(.cpu * 100)% CPU"'
# Output: server-1: 73% CPU
#         server-2: 21% CPU

Ideaal voor samenvattingen en logregels waarbij ruwe JSON ruis zou zijn.

DevOps in de praktijk (patronen 26–30)

Patroon 26 — kubectl: namen van alle draaiende pods

kubectl get pods -o json \
  | jq -r '.items[] | select(.status.phase=="Running") | .metadata.name'

Pipeline: itereer over pods, behoud alleen Running, geef de naam terug als ruwe string.

Patroon 27 — AWS EC2: instance-ID’s met publieke IP’s

aws ec2 describe-instances \
  | jq -r '.Reservations[].Instances[] | [.InstanceId, .PublicIpAddress // "none"] | @tsv'

De //-alternatief-operator levert een terugvalwaarde als het veld null is — waardoor je geen letterlijke null in de uitvoerkolom krijgt.

Patroon 28 — GitHub API: gepagineerde resultaten samenvoegen

for p in 1 2 3; do
  curl -s "https://api.github.com/orgs/myorg/repos?per_page=100&page=$p"
done | jq -s 'add | map(.name)'

-s slurpt alle responses in één array-van-arrays, add voegt ze samen, en map(.name) extraheert namen. Een veelgebruikt patroon voor elke gepagineerde API.

Patroon 29 — Gestructureerde logbestanden filteren

cat app.log | jq -c 'select(.level=="error")'

Dit gaat ervan uit dat het logbestand NDJSON is (één JSON-object per regel). Combineer met tail -f voor live monitoring:

tail -f app.log | jq -c 'select(.level=="error") | {ts: .timestamp, msg: .message}'

Patroon 30 — Docker: alle gebruikte image-namen

docker inspect $(docker ps -q) | jq -r '.[].Config.Image' | sort -u

Handig om snel te controleren welke image-versies op een host draaien.

Veelvoorkomende fouten en hoe je ze oplost

Elke jq-gebruiker loopt hier vroeg of laat tegenaan. De oplossing van tevoren kennen bespaart uren.

Cannot iterate over null (null)

Het veld dat je probeerde te itereren was null of ontbrak. Twee oplossingen:

# Optie A: optionele operator
echo '{}' | jq '.items[]?'
# Output: (niets, geen fout)

# Optie B: alternatieve operator met standaardwaarde
echo '{}' | jq '(.items // [])[]'
# Output: (niets, geen fout)

Gebruik ? als je stilletjes wil overslaan. Gebruik // [] als je een concrete lege array wil afdwingen zodat filters verderop nog steeds worden uitgevoerd.

Cannot index array with "key"

Je schreef .foo maar de huidige waarde is een array. Voeg [] toe om te itereren:

# Fout
echo '{"users":[{"name":"Alice"}]}' | jq '.users.name'
# Error: Cannot index array with "name"

# Goed
echo '{"users":[{"name":"Alice"}]}' | jq '.users[].name'
# Output: "Alice"

Problemen met aanhalingstekens in de shell

Gebruik enkele aanhalingstekens rondom het volledige jq-programma, dubbele aanhalingstekens binnenin voor string-literals:

# Werkt overal
jq '.users[] | select(.role == "admin")'

# Werkt niet — dubbele aanhalingstekens worden eerst door de shell geïnterpreteerd
jq ".users[] | select(.role == \"admin\")"

Randgevallen in Windows PowerShell

PowerShell behandelt enkele aanhalingstekens anders. Gebruik bij voorkeur dubbele aanhalingstekens rondom het programma en escape de binnenste aanhalingstekens, of gebruik een here-string:

jq "@'
.users[] | select(.role == \"admin\")
'@"

Sla bij alles wat niet triviaal is de filter op in een .jq-bestand en voer jq -f filter.jq uit.

Onjuist gebruik van ruwe uitvoer

-r heeft alleen effect op string-resultaten. Een object ermee geven levert gewone JSON op:

echo '{"a":1}' | jq -r '.'
# Output: {"a":1}     ← ongewijzigd; -r had niets te verwijderen

Als je een specifiek veld zonder aanhalingstekens wil, selecteer het dan eerst: jq -r '.a'.

jq wijst JSON met commentaar of trailing comma’s af

echo '{"a": 1, /* note */ "b": 2,}' | jq .
# parse error: Invalid numeric literal

jq volgt strikte RFC 8259 JSON — geen commentaar, geen trailing comma’s, geen sleutels zonder aanhalingstekens. Als het bestand JSON5 of JSONC is (gebruikelijk voor configuratiebestanden), verwijder dan eerst de extensies. De JSON5- en JSONC-formatteerdersgids beschrijft welke parsers ze verwerken en hoe je ze omzet naar strikte JSON voordat je ze naar jq stuurt.

jq versus alternatieven: gron, fx, jj, yq

jq is niet de enige optie, en soms is een andere tool sneller:

ToolSterk puntWanneer je het inzet
gronVlakt JSON af tot grep-bare padenOnbekende schema’s verkennen — je weet niet waar de sleutel zit
fxInteractieve TUI-verkenner met markeringGrote JSON handmatig doorbladeren
jjVeel sneller dan jq, beperkte syntaxisLoops die miljoenen records verwerken
yqDezelfde filtertaal maar voor YAMLKubernetes-manifesten en CI-configuratie
Browser JSON FormatterSyntaxismarkering, nauwkeurige foutmeldingen, geen installatieEén response debuggen tijdens het ontwikkelen

Voor dagelijks shell-werk wint jq op samenstellbaarheid. Voor eenmalige verkenning is gron vaak sneller. Voor YAML gebruik je yq — probeer niet door yq-then-jq te pipen.

Aanbevolen aanpak voor dagelijks gebruik

Een paar gewoonten die jq vertrouwd laten aanvoelen:

  1. Houd een .jqrc bij in $HOME. Plaats hulpfuncties daarin, zodat ze beschikbaar zijn in elke jq-aanroep:

    def running: select(.status.phase == "Running");
    def table(f): [f] | @tsv;
  2. Gebruik jqplay.org voor complexe filters. Plak je JSON links, itereer de filter rechts en zet de werkende versie in je script.

  3. Bouw je eigen spiekbriefje uit history. history | grep 'jq ' | sort -u > ~/jq-patterns.txt legt elk patroon vast dat je daadwerkelijk hebt gebruikt.

  4. Combineer met de browser JSON Formatter voor onbekende schema’s. Verken de structuur visueel om het pad te vinden dat je nodig hebt, en schrijf dan de jq-opdracht.

  5. Bekijk live waarden: watch -n 5 "curl -s api.example.com/health | jq '.uptime'" ververst elke 5 seconden — een snel ops-dashboard zonder afhankelijkheden.

Veelgestelde vragen

Wat is jq en waarom gebruiken ontwikkelaars het?

jq is een JSON-verwerker voor de commandoregel. Het extraheert, filtert en transformeert JSON in shell-pipelines zonder Python- of Node-script — de snelste weg van API-responses, logbestanden of kubectl-uitvoer naar het veld dat je daadwerkelijk nodig hebt.

Is jq beschikbaar op Windows?

Ja. Installeer via winget install jqlang.jq, Chocolatey choco install jq of download de binary van jqlang.org. De regels voor aanhalingstekens in PowerShell verschillen van bash — sla filters bij twijfel op in een .jq-bestand en voer jq -f filter.jq uit.

Hoe verschilt jq van een browser-JSON-formatter?

Een browser-JSON-formatter is interactief — plak JSON, zie markering en fouten, kopieer het resultaat. jq is niet-interactief — beschrijf de transformatie eenmalig en voer die uit in een shell-pipeline. Gebruik de browser om één response te debuggen; gebruik jq om dezelfde bewerking op honderden te automatiseren.

Waarom zegt jq “Cannot iterate over null”?

Je probeerde te itereren (.[]) over een waarde die null is — meestal omdat het veld ontbrak in de invoer. Gebruik de optionele operator .items[]? of geef een standaardwaarde met .items // [] | .[].

Kan jq bestanden in-place wijzigen?

Niet rechtstreeks — jq schrijft naar stdout. Gebruik een tijdelijk bestand of sponge uit moreutils: jq '.version = "2.0"' config.json | sponge config.json. Maak altijd eerst een back-up van het origineel; een verkeerd getypte filter overschrijft het bestand.

Hoe gebruik ik jq met curl-responses?

Geef curl -s door aan jq. De -s-vlag snoert de voortgangsmeter van curl zodat alleen de JSON-body jq bereikt:

curl -s https://api.github.com/users/octocat | jq '.name, .blog'

Wat is het verschil tussen de | van jq en de shell-|?

De shell-pipe stuurt bytes tussen processen. De jq-pipe stuurt JSON-waarden tussen filters binnen één jq-aanroep. Een enkele jq-opdracht met veel interne pipes draait in één proces — goedkoper dan het ketenen van jq | jq | jq.

Kan jq JSON Lines (NDJSON) verwerken?

Ja, standaard. jq leest elke regel als een zelfstandige JSON-waarde wanneer ze worden gescheiden door witruimte. Gebruik -c om NDJSON te produceren en -s om NDJSON in één array te verzamelen.

Hoe druk ik JSON netjes af zonder te filteren?

Gebruik de identiteitsfilter: cat data.json | jq . of gewoon jq . < data.json. Het verwerkt, valideert en drukt netjes af met twee spaties inspringing — geen filter nodig.

Is er een jq-alternatief met een GUI?

Ja. fx biedt een interactieve TUI. Voor een zero-install GUI dekt de JSON Formatter die in je browser draait de meeste behoeften voor verkennen en valideren. Web-tools als jqplay.org bieden jq zelf met een live voorbeeld.

Wanneer gebruik ik jq in plaats van een Python-script te schrijven?

Kies jq wanneer de taak eenmalig is, in een shell-pipeline past en binnen filter-, transformeer- en extraheersemantieken blijft. Stap over op Python als je unit-tests, complexe toestand, externe bibliotheken of vertakkingslogica nodig hebt die een .jq-bestand onleesbaar maakt.

Hoe gebruik ik reguliere expressies in jq?

jq biedt regex via test("patroon"), match("patroon"), capture("patroon") en scan("patroon"), allemaal met PCRE-syntaxis. Geef vlaggen mee als tweede argument: test("abc"; "i") voor hoofdletterongevoelig. match geeft offsets en captures terug; scan geeft elke niet-overlappende overeenkomst.

Kernpunten

  1. Kernmodel eerst: filter in, nul of meer JSON-waarden uit, samenstellen met |. De rest is syntaxis.
  2. Leer per taak, niet per operator: de 30 patronen hierboven dekken ongeveer 95% van dagelijks jq-gebruik.
  3. Verwerk null expliciet: ? voor stil overslaan, // standaard voor een concrete terugvalwaarde. De meeste “Cannot iterate over null”-fixes zijn één van deze twee.
  4. Weet wanneer jq het verkeerde gereedschap is: losse responses horen in een browser-JSON-formatter; YAML hoort in yq; complexe logica hoort in echte code.
  5. Combineer met je bestaande stack: jq schittert in curl-, kubectl-, aws-, docker- en log-pipelines. Gebruik het als bindmiddel, niet als logicalaag.

Zie voor gerelateerde JSON-workflows de JSON5- en JSONC-formatteerdersgids voor syntaxisextensies van configuratiebestanden, en de CSV naar JSON-conversiegids voor gegevensformaatmigraties waarbij jq in de pipeline past. Als je JSON tijdstempels bevat, behandelt de Unix-timestamp-gids de valkuilen die je tegenkomt bij het transformeren van datumvelden.

Gerelateerde artikelen

Alle artikelen bekijken