Cheat Sheet jq: 30 Pola JSON Command-Line Dunia Nyata
Kamu mem-pipe kubectl get pods -o json ke less, lalu terminal membeku di tembok JSON dua megabita. Yang kamu inginkan hanyalah nama setiap pod dengan fase Running. jq mengerjakannya dengan tiga karakter sintaks filter — asalkan kamu kenal kosakatanya.
Ini bukan referensi sintaks lagi. Ini 30 pola yang benar-benar akan kamu ketik, dikelompokkan berdasarkan tugas yang ingin diselesaikan: mengakses, menyaring, mengubah, mengagregasi, memformat, dan menggabungkan dengan alat nyata seperti kubectl, aws, dan docker.
Kapan pakai jq, formatter browser, atau kode?
jq tidak selalu jawaban yang tepat. Tiga pilihan yang jujur:
| Situasi | Alat terbaik | Kenapa |
|---|---|---|
| Satu respons API, butuh syntax highlight dan nomor baris | JSON Formatter di browser | Diff visual, tanpa setup, privat di dalam browser |
| Pipeline shell, pemrosesan log, skrip CI, server jarak jauh | jq | Composable, scriptable, tidak butuh GUI |
| Logika bisnis, unit test, percabangan kompleks | Kode (JS / Python) | Debugger sungguhan, tipe, pustaka |
Pilih jq ketika tugasnya hidup di dalam pipeline shell — selain itu biasanya lebih mudah di tempat lain.
Instalasi dan pipeline pertama
jq hadir sebagai binary tunggal di semua platform utama:
# macOS
brew install jq
# Debian / Ubuntu
sudo apt install jq
# Windows (winget)
winget install jqlang.jq
Pipeline pertama menggunakan filter identitas:
curl -s https://api.github.com/users/octocat | jq .
Filter . mengambil input dan mengeluarkannya apa adanya, rapi. Itu saja sudah menggantikan sebagian besar momen “biar kubuka JSON ini di editor”.
Lima flag mencakup 90% penggunaan nyata:
| Flag | Kegunaan |
|---|---|
-r | Output mentah — menghilangkan tanda kutip di sekitar hasil string |
-c | Kompak — satu nilai JSON per baris (NDJSON) |
-s | Slurp — membaca semua input ke satu array |
-R | Input mentah — membaca baris sebagai string, bukan JSON |
-n | Input null — tidak membaca stdin, memakai null sebagai input |
Model mental inti: filter dan pipe
Sebuah filter menerima satu nilai JSON sebagai input dan menghasilkan nol atau lebih nilai JSON sebagai output. Filter disusun dengan pipe |, yang mengirim setiap output filter kiri sebagai input ke filter kanan. Model mentalnya sama dengan pipe shell, hanya saja yang mengalir adalah nilai JSON, bukan byte.
# . — identitas
echo '{"name":"Alice"}' | jq '.'
# .key — akses field
echo '{"name":"Alice"}' | jq '.name'
# .key.sub — path dalam
echo '{"user":{"email":"a@x.com"}}' | jq '.user.email'
# .[] — iterasi elemen array (menghasilkan banyak output)
echo '[{"id":1},{"id":2}]' | jq '.[] | .id'
# Komposisi pipe: setiap output .items[] masuk ke .name
echo '{"items":[{"name":"a"},{"name":"b"}]}' | jq '.items[] | .name'
Itu seluruh tata bahasanya. 30 pola di bawah adalah kombinasi dari primitif-primitif tersebut.
30 pola yang benar-benar akan kamu pakai
Setiap pola menampilkan JSON input, perintah, dan output. Salin mana saja langsung ke terminalmu.
Akses dan ekstraksi (Pola 1–5)
Pola 1 — Akses aman dengan ?
Mengakses field yang mungkin tidak ada tanpa membuat crash:
echo '{"name":"Alice"}' | jq '.address?.city?'
# Output: null
? menekan error pada kunci yang hilang. Tanpa itu, .address.city akan melempar error tipe jika .address tidak ada.
Pola 2 — Akses path dalam
echo '{"user":{"profile":{"email":"a@x.com"}}}' | jq '.user.profile.email'
# Output: "a@x.com"
Pola 3 — Slicing array
echo '[10,20,30,40,50]' | jq '.[1:3]'
# Output: [20, 30]
echo '[10,20,30,40,50]' | jq '.[-1]'
# Output: 50
Indeks negatif dihitung dari belakang. Slice memakai interval setengah terbuka, seperti Python.
Pola 4 — Turun rekursif untuk menemukan setiap kunci yang cocok
echo '{"a":{"name":"x"},"b":[{"name":"y"},{"id":1}]}' | jq '.. | .name? | select(. != null)'
# Output: "x"
# "y"
.. menelusuri setiap nilai dalam pohon. Digabung dengan .name? dan select, ia mengekstrak setiap field name di kedalaman berapa pun — sangat berguna untuk mengeksplorasi skema JSON yang belum dikenal.
Pola 5 — Daftar semua kunci objek
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 mengurutkan alfabetis; keys_unsorted mempertahankan urutan penyisipan.
Menyaring (Pola 6–10)
Pola 6 — Menyaring array berdasarkan kondisi
echo '[{"age":20},{"age":30},{"age":40}]' | jq 'map(select(.age > 25))'
# Output: [{"age":30},{"age":40}]
map(f) menerapkan f pada tiap elemen; select(cond) hanya menyimpan elemen yang memenuhi kondisi.
Pola 7 — Mencocokkan awalan string
echo '[{"name":"api-gateway"},{"name":"web-ui"},{"name":"api-auth"}]' \
| jq '.[] | select(.name | startswith("api"))'
# Output: {"name":"api-gateway"}
# {"name":"api-auth"}
Yang juga berguna: endswith("..."), contains("..."), test("^regex$").
Pola 8 — Kondisi gabungan
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 bekerja sesuai dugaan.
Pola 9 — Hapus field sensitif
echo '{"user":"alice","password":"s3cret","token":"abc"}' | jq 'del(.password, .token)'
# Output: {"user":"alice"}
del() menerima banyak path dan tidak gagal jika salah satunya hilang.
Pola 10 — Deduplikasi berdasarkan field
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 mendeduplikasi nilai utuh; unique_by(f) mendeduplikasi berdasarkan hasil filter.
Mengubah (Pola 11–15)
Pola 11 — Mengganti nama field
echo '[{"first_name":"Alice","age":30}]' | jq 'map({name: .first_name, age})'
# Output: [{"name":"Alice","age":30}]
Bentuk singkat {age} setara dengan {age: .age}.
Pola 12 — Menambah field terhitung dengan interpolasi string
echo '[{"first":"Alice","last":"Chen"}]' \
| jq 'map(. + {fullName: "\(.first) \(.last)"})'
# Output: [{"first":"Alice","last":"Chen","fullName":"Alice Chen"}]
\(expr) mengevaluasi expr dan menyisipkan nilainya ke string.
Pola 13 — Meratakan array bertingkat
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 menerima argumen kedalaman opsional: flatten(1) hanya mengupas satu level.
Pola 14 — Objek ke array dan sebaliknya
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}
Pasangan ini memungkinkan transformasi yang membutuhkan iterasi atas kunci objek — hal yang tidak bisa dilakukan langsung oleh sintaks titik.
Pola 15 — Menggabungkan dua objek secara mendalam
echo '{"a":{"x":1},"b":2}' | jq '. * {a:{y:9}, c:3}'
# Output: {"a":{"x":1,"y":9},"b":2,"c":3}
Operator * melakukan deep merge. Untuk merge dangkal pakai + (sisi kanan menang).
Agregasi (Pola 16–20)
Pola 16 — Panjang array, objek, dan string
echo '[1,2,3,4]' | jq 'length' # 4
echo '{"a":1,"b":2}' | jq 'length' # 2
echo '"hello"' | jq 'length' # 5
Pola 17 — Menjumlahkan field
echo '[{"price":10},{"price":25},{"price":5}]' | jq '[.[].price] | add'
# Output: 40
add menjumlah angka, menggabungkan string, atau memfusikan array — tergantung tipe input.
Pola 18 — Pengelompokan berdasarkan field
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}]]
Setiap grup menjadi array dalam. Gabung dengan map untuk agregasi per grup.
Pola 19 — Pengurutan menurun
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"}]
String tanggal ISO 8601 urut dengan benar sebagai string. Format lain perlu di-parse dulu — panduan Unix timestamp membahas epoch detik, milidetik, dan konversi zona waktu secara rinci.
Pola 20 — Maksimum atau minimum berdasarkan field
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, max_by mengembalikan satu elemen. Untuk top N pakai sort_by(.rating) | reverse | .[:N].
Format output (Pola 21–25)
Pola 21 — Output CSV
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
| jq -r '.[] | [.name, .age] | @csv'
# Output: "Alice",30
# "Bob",25
@csv mengutip string dan mengescape kutipan internal. -r menghapus kutipan JSON luar supaya CSV langsung bisa dipipe. Untuk konversi bolak-balik penuh antara CSV dan JSON dalam pipeline, lihat panduan konversi CSV ke JSON.
Pola 22 — Output TSV
echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' \
| jq -r '.[] | [.id, .name] | @tsv'
# Output: 1 Alice
# 2 Bob
Output yang dipisah tab cocok dengan cut, awk, dan column -t.
Pola 23 — Output string mentah
echo '["alpha","beta"]' | jq -r '.[]'
# Output: alpha
# beta
Tanpa -r, setiap baris akan berkutip. Output mentah adalah yang kamu kirim ke xargs, while read, atau perintah shell lain.
Pola 24 — NDJSON / JSON Lines
echo '[{"a":1},{"a":2}]' | jq -c '.[]'
# Output: {"a":1}
# {"a":2}
Setiap baris adalah nilai JSON mandiri — format yang dipakai Kafka, Elasticsearch, dan kebanyakan logger terstruktur. -c juga membuang semua whitespace internal.
Pola 25 — Interpolasi string untuk output terformat
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
Bagus untuk ringkasan dan baris log di mana JSON mentah jadi kebisingan.
DevOps di lapangan (Pola 26–30)
Pola 26 — kubectl: nama setiap pod yang sedang berjalan
kubectl get pods -o json \
| jq -r '.items[] | select(.status.phase=="Running") | .metadata.name'
Pipeline: iterasi pod, simpan hanya Running, emit nama sebagai string mentah.
Pola 27 — AWS EC2: ID instance dengan IP publik
aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] | [.InstanceId, .PublicIpAddress // "none"] | @tsv'
Operator alternatif // memberi nilai cadangan saat field null — menghindari null harfiah di kolom output.
Pola 28 — GitHub API: menggabungkan hasil paginasi
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 menampung semua respons sebagai array of arrays, add menggabungkannya, lalu map(.name) mengekstrak nama. Pola umum untuk API paginasi apa pun.
Pola 29 — Menyaring file log terstruktur
cat app.log | jq -c 'select(.level=="error")'
Asumsinya file log berformat NDJSON (satu objek JSON per baris). Gabung dengan tail -f untuk monitoring langsung:
tail -f app.log | jq -c 'select(.level=="error") | {ts: .timestamp, msg: .message}'
Pola 30 — Docker: semua nama image yang sedang dipakai
docker inspect $(docker ps -q) | jq -r '.[].Config.Image' | sort -u
Praktis untuk cek cepat versi image yang berjalan di sebuah host.
Error umum dan cara memperbaikinya
Setiap pengguna jq menabrak yang ini. Tahu solusinya lebih awal hemat berjam-jam.
Cannot iterate over null (null)
Field input yang kamu iterasi bernilai null atau hilang. Dua perbaikan:
# Opsi A: operator opsional
echo '{}' | jq '.items[]?'
# Output: (tidak ada, tanpa error)
# Opsi B: operator alternatif dengan default
echo '{}' | jq '(.items // [])[]'
# Output: (tidak ada, tanpa error)
Pakai ? kalau ingin melompat diam-diam. Pakai // [] kalau ingin memaksa array kosong konkret supaya filter berikutnya tetap jalan.
Cannot index array with "key"
Kamu menulis .foo padahal nilai saat ini adalah array. Tambahkan [] untuk iterasi:
# Salah
echo '{"users":[{"name":"Alice"}]}' | jq '.users.name'
# Error: Cannot index array with "name"
# Benar
echo '{"users":[{"name":"Alice"}]}' | jq '.users[].name'
# Output: "Alice"
Masalah kutipan shell
Bungkus seluruh program jq dengan kutip tunggal, pakai kutip ganda di dalam untuk literal string:
# Aman di mana saja
jq '.users[] | select(.role == "admin")'
# Rusak — kutip ganda ditafsir shell lebih dulu
jq ".users[] | select(.role == \"admin\")"
Kasus pinggir PowerShell Windows
PowerShell tidak memperlakukan kutip tunggal dengan cara yang sama. Lebih baik pakai kutip ganda di sekitar program dan escape kutipan dalam, atau pakai here-string:
jq "@'
.users[] | select(.role == \"admin\")
'@"
Untuk hal-hal non-sepele, simpan filter dalam file .jq dan jalankan jq -f filter.jq.
Salah pakai -r
-r hanya berpengaruh pada hasil bertipe string. Kalau dipakai pada objek, yang keluar tetap objek JSON biasa:
echo '{"a":1}' | jq -r '.'
# Output: {"a":1} ← tidak berubah; -r tidak punya yang perlu dihapus
Kalau ingin field tertentu tanpa kutip, pilih dulu field itu: jq -r '.a'.
jq menolak JSON dengan komentar atau koma akhir
echo '{"a": 1, /* catatan */ "b": 2,}' | jq .
# parse error: Invalid numeric literal
jq mengikuti RFC 8259 JSON secara ketat — tanpa komentar, tanpa koma akhir, tanpa kunci tanpa kutip. Jika file-nya JSON5 atau JSONC (umum pada file konfigurasi), bersihkan ekstensi tersebut sebelum mem-pipe ke jq. Panduan format JSON5 dan JSONC menjelaskan parser mana yang mendukungnya dan cara mengubahnya menjadi JSON ketat.
jq vs alternatif: gron, fx, jj, yq
jq bukan satu-satunya, dan kadang alat lain lebih cepat:
| Alat | Keunggulan | Kapan dipakai |
|---|---|---|
| gron | Meratakan JSON jadi path yang bisa di-grep | Mengeksplorasi skema asing — kamu tidak tahu di mana kuncinya |
| fx | Eksplorer TUI interaktif dengan highlight | Membaca JSON besar dengan mata |
| jj | Jauh lebih cepat dari jq, sintaks terbatas | Loop panas yang memproses jutaan rekaman |
| yq | Bahasa filter sama tapi untuk YAML | Manifest Kubernetes dan konfigurasi CI |
| JSON Formatter di browser | Syntax highlight, pesan error presisi, tanpa instalasi | Debug satu respons ketika sedang mengembangkan |
Untuk kerja shell harian, jq menang di komposisi. Untuk eksplorasi sekali-sekali, gron sering lebih cepat. Untuk YAML pakai yq — jangan mencoba pipe yq lalu jq.
Trik pro untuk pemakaian harian
Beberapa kebiasaan yang bikin jq terasa alami:
-
Simpan
.jqrcdi$HOME. Taruh fungsi pembantu di sana, dan semuanya tersedia di setiap panggilanjq:def running: select(.status.phase == "Running"); def table(f): [f] | @tsv; -
Pakai jqplay.org untuk filter kompleks. Tempel JSON di kiri, ulik filter di kanan, pindahkan versi yang jalan ke skripmu.
-
Bangun cheat sheet pribadi dari
history.history | grep 'jq ' | sort -u > ~/jq-patterns.txtmenangkap setiap pola yang benar-benar pernah kamu pakai. -
Kombinasikan dengan JSON Formatter di browser untuk skema yang asing. Jelajahi struktur secara visual dulu untuk menemukan path yang dibutuhkan, baru tulis perintah
jq. -
Pantau nilai langsung:
watch -n 5 "curl -s api.example.com/health | jq '.uptime'"menyegarkan setiap 5 detik — dashboard ops mini tanpa dependensi.
FAQ
Apa itu jq dan kenapa pengembang memakainya?
jq adalah prosesor JSON untuk command line. Ia mengekstrak, menyaring, dan mengubah JSON di pipeline shell tanpa skrip Python atau Node — jalur terpendek dari respons API, file log, atau output kubectl ke field yang kamu butuhkan.
Apakah jq tersedia di Windows?
Tersedia. Instal via winget install jqlang.jq, Chocolatey choco install jq, atau unduh binary dari jqlang.org. Aturan kutip PowerShell berbeda dari bash — kalau ragu, simpan filter di file .jq dan jalankan jq -f filter.jq.
Apa bedanya jq dengan JSON formatter di browser?
JSON Formatter di browser bersifat interaktif — tempel JSON, lihat highlight dan error, salin hasil. jq non-interaktif — jelaskan transformasi sekali, jalankan di pipeline shell. Pakai browser untuk debug satu respons; pakai jq untuk otomatisasi operasi yang sama pada ratusan input.
Kenapa jq bilang “Cannot iterate over null”?
Kamu mencoba iterasi (.[]) atas nilai null — biasanya karena field tidak ada di input. Perbaiki dengan operator opsional .items[]? atau beri default lewat .items // [] | .[].
Bisakah jq mengubah file di tempat?
Tidak langsung — jq menulis ke stdout. Pakai file sementara atau sponge dari moreutils: jq '.version = "2.0"' config.json | sponge config.json. Selalu cadangkan file asli dulu; filter yang salah ketik akan menimpa file.
Bagaimana memakai jq dengan respons curl?
Pipe curl -s ke jq. Flag -s membungkam progress bar curl supaya hanya body JSON yang sampai ke jq:
curl -s https://api.github.com/users/octocat | jq '.name, .blog'
Apa bedanya | di jq dengan | di shell?
Pipe shell memindahkan byte antar-proses. Pipe jq memindahkan nilai JSON antar-filter dalam satu pemanggilan jq. Perintah dengan banyak pipe internal berjalan di satu proses — lebih murah daripada rantai jq | jq | jq.
Apakah jq bisa menangani JSON Lines (NDJSON)?
Bisa, secara native. jq membaca setiap baris sebagai nilai JSON mandiri saat dipisahkan whitespace. Pakai -c untuk mengeluarkan NDJSON dan -s untuk mengumpulkan NDJSON menjadi satu array.
Bagaimana memformat JSON tanpa memfilter?
Pakai filter identitas: cat data.json | jq . atau jq . < data.json. Ia mem-parse, memvalidasi, dan memformat dengan indent dua spasi — tanpa filter.
Adakah alternatif jq dengan GUI?
Ada. fx menyediakan TUI interaktif. Untuk GUI tanpa instalasi, JSON Formatter berbasis browser mencakup kebutuhan eksplorasi dan validasi. Alat web seperti jqplay.org menyediakan jq sendiri dengan preview langsung.
Kapan pakai jq alih-alih menulis skrip Python?
Pilih jq saat tugasnya sekali jalan, muat di pipeline shell, dan tetap dalam semantik saring/ubah/ekstrak. Pindah ke Python kalau butuh unit test, state kompleks, pustaka pihak ketiga, atau logika bercabang yang melebihi keterbacaan file .jq.
Bagaimana memakai regex di jq?
jq memaparkan regex lewat test("pattern"), match("pattern"), capture("pattern"), dan scan("pattern"), semuanya dalam sintaks PCRE. Berikan flag sebagai argumen kedua: test("abc"; "i") untuk abaikan huruf besar/kecil. match mengembalikan offset dan capture; scan mengeluarkan setiap kecocokan yang tidak tumpang tindih.
Bagaimana menjaga karakter non-ASCII tetap utuh di output jq?
jq mengeluarkan UTF-8 secara default dan mempertahankan karakter non-ASCII selama kamu tidak memakai -a / --ascii-output. Kalau muncul \u00e9 atau \u4e2d\u6587 menggantikan karakter aslinya, biasanya locale terminal penyebabnya: pastikan $LANG adalah id_ID.UTF-8 atau en_US.UTF-8 dan hindari flag -a.
Poin-poin utama
- Model mental dulu: satu filter masuk, nol atau lebih nilai JSON keluar, disusun dengan
|. Sisanya cuma sintaks. - Belajar per tugas, bukan per operator: 30 pola di atas mencakup sekitar 95% pemakaian
jqharian. - Tangani null secara eksplisit:
?untuk melompat diam-diam,// defaultuntuk fallback konkret. Sebagian besar perbaikanCannot iterate over nulllewat salah satu dari keduanya. - Tahu kapan
jqadalah alat yang salah: respons tunggal lebih cocok di JSON Formatter browser; YAML milikyq; logika kompleks milik kode nyata. - Pasangkan dengan stack yang ada:
jqbersinar di dalamcurl,kubectl,aws,docker, dan pipeline log. Pakailah sebagai lem, bukan lapisan logika.
Untuk alur JSON terkait, lihat panduan format JSON5 dan JSONC untuk ekstensi sintaks file konfigurasi, dan panduan konversi CSV ke JSON untuk migrasi format data di mana jq masuk ke dalam pipeline. Kalau JSON-mu punya timestamp, panduan Unix timestamp membahas jebakan saat mengubah field tanggal.