jq Transform Patterns
Essential jq patterns for processing API responses.
Basic Navigation
# Get field
echo '{"name": "test"}' | jq '.name'
# Nested field
echo '{"data": {"id": 123}}' | jq '.data.id'
# Array element
echo '[1,2,3]' | jq '.[0]'
# All array elements
echo '[{"a":1},{"a":2}]' | jq '.[].a'
Extract Fields
# Extract specific fields
curl -ks ... | jq '.items[] | {id, name, status}'
# Rename fields
curl -ks ... | jq '.items[] | {endpoint_id: .id, endpoint_name: .name}'
# Flatten nested
curl -ks ... | jq '.data.users[] | {name: .profile.name, email: .contact.email}'
Filter with select()
# Filter with select
curl -ks ... | jq '.items[] | select(.status == "active")'
# Multiple conditions
curl -ks ... | jq '.items[] | select(.status == "active" and .type == "user")'
# Regex matching
curl -ks ... | jq '.items[] | select(.name | test("^prod-"))'
# Null-safe filtering
curl -ks ... | jq '.items[] | select(.email != null and .email != "")'
Array Transformations
# Map over array
curl -ks ... | jq '[.items[] | .name]'
# Unique values
curl -ks ... | jq '[.items[].type] | unique'
# Sort
curl -ks ... | jq '.items | sort_by(.created_at) | reverse'
# Group by field
curl -ks ... | jq 'group_by(.type) | map({type: .[0].type, count: length})'
Aggregation
# Count
curl -ks ... | jq '.items | length'
# Sum
curl -ks ... | jq '[.items[].size] | add'
# Min/Max
curl -ks ... | jq '[.items[].value] | max'
# Average
curl -ks ... | jq '[.items[].score] | add / length'
Object Construction
# Build new object
curl -ks ... | jq '{
total: .items | length,
active: [.items[] | select(.status == "active")] | length,
types: [.items[].type] | unique
}'
# Add computed fields
curl -ks ... | jq '.items[] | . + {full_name: "\(.first) \(.last)"}'
ISE-Specific Patterns
# ISE ERS: Extract endpoint MACs
netapi ise ers endpoints --format json | jq -r '.[] | .mac'
# ISE ERS: Endpoints with identity group
netapi ise ers endpoints --format json | \
jq -r '.[] | select(.groupId != null) | "\(.mac) \(.groupId)"'
# ISE ERS: Pivot table by group
netapi ise ers endpoints --format json | \
jq 'group_by(.groupId) | map({
group: .[0].groupId,
count: length,
macs: [.[].mac]
})'
Vault Patterns
# Vault: Extract cert fields
vault read -format=json pki_int/cert/serial | jq '{
cn: .data.certificate | @base64d | ... ,
expiry: .data.expiration
}'
# Vault: List secrets with metadata
vault kv list -format=json kv/ | jq -r '.[]' | while read key; do
vault kv get -format=json "kv/$key" | jq "{key: \"$key\", version: .data.metadata.version}"
done
Kubernetes Patterns
# k8s: Pod status summary
kubectl get pods -o json | jq '.items[] | {
name: .metadata.name,
ready: (.status.containerStatuses // [] | map(select(.ready)) | length),
total: (.spec.containers | length),
restarts: ([.status.containerStatuses // [] | .[].restartCount] | add)
}'
# k8s: Resource requests
kubectl get pods -o json | jq '[.items[].spec.containers[].resources.requests.memory // "0"] |
map(gsub("Mi"; "") | tonumber) | add'
Table Output
# Format as table (TSV)
curl -ks ... | jq -r '.items[] | [.id, .name, .status] | @tsv'
# Format as CSV
curl -ks ... | jq -r '.items[] | [.id, .name, .status] | @csv'
# With headers
curl -ks ... | jq -r '
["ID", "NAME", "STATUS"],
(.items[] | [.id, .name, .status])
| @tsv
'
# Padded columns with awk
curl -ks ... | jq -r '.items[] | [.id, .name, .status] | @tsv' | \
awk -F'\t' '{printf "%-10s %-20s %-10s\n", $1, $2, $3}'
Recursive Search
# Find all keys named "error" at any depth
curl -ks ... | jq '.. | .error? // empty'
# Find paths to specific value
curl -ks ... | jq 'paths(. == "error") | join(".")'
# Flatten deeply nested structure
curl -ks ... | jq '[leaf_paths as $p | {path: $p | join("."), value: getpath($p)}]'
String Manipulation
# Split and extract
curl -ks ... | jq -r '.name | split("-")[0]'
# Regex capture
curl -ks ... | jq -r '.dn | capture("CN=(?<cn>[^,]+)") | .cn'
# Case conversion
curl -ks ... | jq '.name | ascii_downcase'
# String interpolation
curl -ks ... | jq -r '"User: \(.name) (\(.email))"'
Null Handling
# Default for null
curl -ks ... | jq '.optional_field // "default"'
# Skip nulls in array
curl -ks ... | jq '[.items[].value | select(. != null)]'
# Empty string for null
curl -ks ... | jq '.field // ""'
# Null-safe chaining
curl -ks ... | jq '.data.nested?.field? // "not found"'