jq - JSON Command-Line Processor
jq is a lightweight and flexible command-line JSON processor. Think of it as `sed` for JSON data.
Basic Syntax
Identity Filter
jq '.' file.json
Returns the input unchanged, but pretty-printed.
Array Length
jq 'length' file.json
Count elements in an array.
Array Access
jq '.[0]' file.json # First element
jq '.[5]' file.json # Sixth element (0-indexed)
Field Access
jq '.[0].name' file.json # Get name field from first element
jq '.[0].stats.hp' file.json # Nested field access
Array Operations
Iterator
jq '.[]' file.json # Unwrap array, output each element
jq '.[].name' file.json # Get name from each element
Array Slicing
jq '.[0:3]' file.json # First 3 elements
jq '.[5:10]' file.json # Elements 5-9
Creating Arrays
jq '[.[].name]' file.json # Collect all names into array
Pipe Operator
Chain operations together (like Unix pipes):
jq '.[] | select(.region == "Kanto") | .name' file.json
Filtering with select()
Basic Filtering
# Find legendary Pokemon
jq '.[] | select(.legendary == true)' file.json
# Find by region
jq '.[] | select(.region == "Kanto")' file.json
# Multiple conditions
jq '.[] | select(.type | contains(["Fire"]) and .stats.speed > 80)' file.json
Collect Filtered Results
# Return as array
jq '[.[] | select(.legendary == true) | .name]' file.json
Working with Nested Data
Accessing Nested Objects
# Get data from nested results object
jq '.results[].name' file.json
jq '.results[] | {name: .name, type: .type}' file.json
Restructuring Output
# Create custom structure
jq '{results: [.results[] | {name: .name, type: .type}]}' file.json
Unique Values
Get Distinct Values
jq '[.[].region] | unique' file.json
Flatten Nested Arrays
# Get all unique types from array of type arrays
jq '[.[].type | .[]] | unique' file.json
Breaking down .[].type | .[]:
- First
.[]iterates through Pokemon .typegets the type array- Second
.[]unwraps each type array into individual strings
Grouping and Counting
Group By
# Count Pokemon by region
jq 'group_by(.region) | map({region: .[0].region, count: length})' file.json
Count by Type
# Count occurrences of each type
jq '[.[] | .type[]] | group_by(.) | map({type: .[0], count: length})' file.json
Aggregation Functions
add - Sum Array
echo '[10, 20, 30, 40]' | jq 'add'
# Output: 100
length - Count Elements
echo '[10, 20, 30, 40]' | jq 'length'
# Output: 4
Average (add / length)
echo '[10, 20, 30, 40]' | jq 'add / length'
# Output: 25
Calculate Stats by Group
# Average HP by region
jq 'group_by(.region) | map({
region: .[0].region,
avg_hp: (map(.stats.hp) | add / length),
count: length
})' file.json
Sorting
# Sort by field
jq 'sort_by(.name)' file.json
# Reverse sort
jq 'sort_by(.stats.speed) | reverse' file.json
Creating Custom Objects
Basic Object Construction
jq '.[] | {name: .name, region: .region, is_legendary: .legendary}' file.json
Computed Fields
jq '.[] | {
name: .name,
total_hp: .stats.hp,
is_fast: (.stats.speed > 100)
}' file.json
Conditional Logic
if-then-else
jq 'map(
if .name == "Eevee" then
.evolves_to = ["Vaporeon", "Jolteon", "Flareon"]
elif .evolves_to == null then
.evolves_to = []
else
.evolves_to = [.evolves_to]
end
)' file.json
Useful Flags
-c (Compact Output)
jq -c '.[] | {name: .name, type: .type}' file.json
One JSON object per line, no pretty-printing.
-r (Raw Output)
jq -r '.results[] | "\(.name): \(.type | join(", "))"' file.json
Output raw strings without JSON quotes.
-s (Slurp)
jq -s '.' file1.json file2.json
Read multiple JSON files into a single array.
Common Patterns
Check Data Structure
jq '. | type' file.json # Check root type (object/array)
jq 'keys' file.json # Get object keys
jq '.[0] | keys' file.json # Get keys from first element
Limit Results
jq '.results[0:10]' file.json # First 10 results
jq '.results[-5:]' file.json # Last 5 results
Count Occurrences
jq '[.[] | select(.region == "Kanto")] | length' file.json
Find Min/Max
jq '[.[].stats.speed] | max' file.json
jq '[.[].stats.speed] | min' file.json
Practical Examples
Extract Specific Fields to New File
jq '{results: [.results[] | {name: .name, type: .type}]}' input.json > output.json
Filter and Transform
# Get all Fire-type Pokemon with speed > 80
jq '[.[] | select((.type | contains(["Fire"])) and .stats.speed > 80) |
{name: .name, speed: .stats.speed}]' pokemon.json
Update Field Values
# Convert single value to array for all entries
jq 'map(
if .evolves_to == null then
.evolves_to = []
else
.evolves_to = [.evolves_to]
end
)' input.json > output.json
Tips
- Use
|liberally - Break complex queries into pipeline steps - Test incrementally - Build queries step by step
- Wrap in
[]to collect results into an array - Use
-cfor compact output when piping to other tools - Check structure first with
jq 'keys'orjq '.[0]'
Resources
- Official Manual: https://jqlang.github.io/jq/manual/
- jq Play (online): https://jqplay.org/
- Tutorial: https://stedolan.github.io/jq/tutorial/