362 lines
6.5 KiB
Markdown
362 lines
6.5 KiB
Markdown
# jq: JSON Query and Extraction Reference
|
|
|
|
**Goal: Extract specific data from JSON without reading entire file.**
|
|
|
|
## The Essential Pattern
|
|
|
|
```bash
|
|
jq '.field' file.json
|
|
```
|
|
|
|
Use `-r` flag for raw output (removes quotes from strings):
|
|
```bash
|
|
jq -r '.field' file.json
|
|
```
|
|
|
|
**Use `-r` by default for string values** - cleaner output.
|
|
|
|
---
|
|
|
|
# Core Patterns (80% of Use Cases)
|
|
|
|
## 1. Extract Top-Level Field
|
|
```bash
|
|
jq -r '.version' package.json
|
|
jq -r '.name' package.json
|
|
```
|
|
|
|
## 2. Extract Nested Field
|
|
```bash
|
|
jq -r '.dependencies.react' package.json
|
|
jq -r '.scripts.build' package.json
|
|
jq -r '.config.database.host' config.json
|
|
```
|
|
|
|
## 3. Extract Multiple Fields
|
|
```bash
|
|
jq '{name, version, description}' package.json
|
|
```
|
|
Creates object with just those fields.
|
|
|
|
Or as separate lines:
|
|
```bash
|
|
jq -r '.name, .version' package.json
|
|
```
|
|
|
|
## 4. Extract from Array by Index
|
|
```bash
|
|
jq '.[0]' array.json # First element
|
|
jq '.items[2]' data.json # Third element
|
|
```
|
|
|
|
## 5. Extract All Array Elements
|
|
```bash
|
|
jq '.[]' array.json # All elements
|
|
jq '.items[]' data.json # All items
|
|
```
|
|
|
|
## 6. Extract Field from Each Array Element
|
|
```bash
|
|
jq -r '.dependencies | keys[]' package.json # All dependency names
|
|
jq -r '.items[].name' data.json # Name from each item
|
|
```
|
|
|
|
## 7. Filter Array by Condition
|
|
```bash
|
|
jq '.items[] | select(.active == true)' data.json
|
|
jq '.items[] | select(.price > 100)' data.json
|
|
```
|
|
|
|
## 8. Get Object Keys
|
|
```bash
|
|
jq -r 'keys[]' object.json
|
|
jq -r '.dependencies | keys[]' package.json
|
|
```
|
|
|
|
## 9. Check if Field Exists
|
|
```bash
|
|
jq 'has("field")' file.json
|
|
```
|
|
|
|
## 10. Handle Missing Fields (Use // for Default)
|
|
```bash
|
|
jq -r '.field // "default"' file.json
|
|
```
|
|
|
|
---
|
|
|
|
# Common Real-World Workflows
|
|
|
|
## "What version is this package?"
|
|
```bash
|
|
jq -r '.version' package.json
|
|
```
|
|
|
|
## "What's the main entry point?"
|
|
```bash
|
|
jq -r '.main' package.json
|
|
```
|
|
|
|
## "List all dependencies"
|
|
```bash
|
|
jq -r '.dependencies | keys[]' package.json
|
|
```
|
|
|
|
## "What version of React?"
|
|
```bash
|
|
jq -r '.dependencies.react' package.json
|
|
```
|
|
|
|
## "List all scripts"
|
|
```bash
|
|
jq -r '.scripts | keys[]' package.json
|
|
```
|
|
|
|
## "Get specific script command"
|
|
```bash
|
|
jq -r '.scripts.build' package.json
|
|
```
|
|
|
|
## "Check TypeScript compiler options"
|
|
```bash
|
|
jq '.compilerOptions' tsconfig.json
|
|
```
|
|
|
|
## "Get target from tsconfig"
|
|
```bash
|
|
jq -r '.compilerOptions.target' tsconfig.json
|
|
```
|
|
|
|
## "List all services from docker-compose JSON"
|
|
```bash
|
|
jq -r '.services | keys[]' docker-compose.json
|
|
```
|
|
|
|
## "Get environment variables for a service"
|
|
```bash
|
|
jq '.services.api.environment' docker-compose.json
|
|
```
|
|
|
|
---
|
|
|
|
# Advanced Patterns (20% Use Cases)
|
|
|
|
## Combine Multiple Queries
|
|
```bash
|
|
jq '{version, deps: (.dependencies | keys)}' package.json
|
|
```
|
|
|
|
## Map Array Elements
|
|
```bash
|
|
jq '[.items[] | .name]' data.json # Array of names
|
|
```
|
|
|
|
## Count Array Length
|
|
```bash
|
|
jq '.items | length' data.json
|
|
jq '.dependencies | length' package.json
|
|
```
|
|
|
|
## Sort Array
|
|
```bash
|
|
jq '.items | sort_by(.name)' data.json
|
|
```
|
|
|
|
## Group and Transform
|
|
```bash
|
|
jq 'group_by(.category)' data.json
|
|
```
|
|
|
|
## Complex Filter
|
|
```bash
|
|
jq '.items[] | select(.active and .price > 100) | .name' data.json
|
|
```
|
|
|
|
---
|
|
|
|
# Pipe Composition
|
|
|
|
jq uses `|` for piping within queries:
|
|
```bash
|
|
jq '.items | map(.name) | sort' data.json
|
|
```
|
|
|
|
Can also pipe to shell commands:
|
|
```bash
|
|
jq -r '.dependencies | keys[]' package.json | wc -l # Count dependencies
|
|
jq -r '.dependencies | keys[]' package.json | sort # Sorted dependency list
|
|
```
|
|
|
|
---
|
|
|
|
# Common Flags
|
|
|
|
- `-r` - Raw output (no quotes) - **USE THIS FOR STRINGS**
|
|
- `-c` - Compact output (single line)
|
|
- `-e` - Exit with error if output is false/null
|
|
- `-S` - Sort object keys
|
|
- `-M` - Monochrome (no colors)
|
|
|
|
**Default to `-r` for string extraction.**
|
|
|
|
---
|
|
|
|
# Handling Edge Cases
|
|
|
|
## If Field Might Not Exist
|
|
```bash
|
|
jq -r '.field // "not found"' file.json
|
|
```
|
|
|
|
## If Result Might Be Null
|
|
```bash
|
|
jq -r '.field // empty' file.json # Output nothing if null
|
|
```
|
|
|
|
## If Array Might Be Empty
|
|
```bash
|
|
jq -r '.items[]? // empty' file.json # ? suppresses errors
|
|
```
|
|
|
|
## Multiple Possible Paths
|
|
```bash
|
|
jq -r '.field1 // .field2 // "default"' file.json
|
|
```
|
|
|
|
---
|
|
|
|
# Error Handling
|
|
|
|
If field doesn't exist:
|
|
```bash
|
|
# BAD: jq '.nonexistent' file.json
|
|
# → null (but no error)
|
|
|
|
# GOOD: Check existence first
|
|
jq -e 'has("field")' file.json && jq '.field' file.json
|
|
```
|
|
|
|
Or use default:
|
|
```bash
|
|
jq -r '.field // "not found"' file.json
|
|
```
|
|
|
|
---
|
|
|
|
# Integration with Other Tools
|
|
|
|
## With ast-grep
|
|
```bash
|
|
# Get dependencies, then search code for usage
|
|
jq -r '.dependencies | keys[]' package.json | while read dep; do
|
|
rg -l "from ['\"]$dep['\"]"
|
|
done
|
|
```
|
|
|
|
## With Edit Tool
|
|
Common workflow:
|
|
1. Use jq to extract current value
|
|
2. Modify value
|
|
3. Use Edit tool to update JSON (or jq for complex updates)
|
|
|
|
## Reading STDIN
|
|
```bash
|
|
echo '{"key":"value"}' | jq -r '.key'
|
|
```
|
|
|
|
---
|
|
|
|
# Best Practices
|
|
|
|
## 1. Always Use -r for String Fields
|
|
```bash
|
|
# BAD: jq '.version' package.json → "1.0.0" (with quotes)
|
|
# GOOD: jq -r '.version' package.json → 1.0.0 (raw)
|
|
```
|
|
|
|
## 2. Test Queries on Small Examples First
|
|
```bash
|
|
echo '{"test":"value"}' | jq -r '.test'
|
|
```
|
|
|
|
## 3. Use // for Defaults
|
|
```bash
|
|
jq -r '.field // "default"' file.json
|
|
```
|
|
|
|
## 4. Use keys[] for Object Properties
|
|
```bash
|
|
jq -r 'keys[]' object.json
|
|
```
|
|
|
|
## 5. Combine with Shell Pipes
|
|
```bash
|
|
jq -r '.dependencies | keys[]' package.json | grep react
|
|
```
|
|
|
|
---
|
|
|
|
# Quick Reference
|
|
|
|
## Most Common Commands
|
|
|
|
```bash
|
|
# Single field
|
|
jq -r '.field' file.json
|
|
|
|
# Nested field
|
|
jq -r '.parent.child' file.json
|
|
|
|
# Array element
|
|
jq '.array[0]' file.json
|
|
|
|
# All array elements
|
|
jq '.array[]' file.json
|
|
|
|
# Object keys
|
|
jq -r 'keys[]' file.json
|
|
|
|
# Filter array
|
|
jq '.array[] | select(.field == "value")' file.json
|
|
|
|
# Multiple fields
|
|
jq '{field1, field2}' file.json
|
|
|
|
# With default
|
|
jq -r '.field // "default"' file.json
|
|
```
|
|
|
|
---
|
|
|
|
# When to Use Read Instead
|
|
|
|
Use Read tool when:
|
|
- File is < 50 lines
|
|
- Need to see overall structure
|
|
- Making edits (need full context)
|
|
- Exploring unknown JSON structure
|
|
|
|
Use jq when:
|
|
- File is large
|
|
- Know exactly what field(s) are needed
|
|
- Want to save context tokens
|
|
|
|
---
|
|
|
|
# Summary
|
|
|
|
**Default pattern:**
|
|
```bash
|
|
jq -r '.field' file.json
|
|
```
|
|
|
|
**Key principles:**
|
|
1. Use `-r` for string output (raw, no quotes)
|
|
2. Use `.` notation for nested fields
|
|
3. Use `[]` for array access
|
|
4. Use `//` for defaults
|
|
5. Use `keys[]` for object properties
|
|
6. Pipe with `|` inside jq, pipe to shell after
|
|
|
|
**Massive context savings: Extract only what is needed instead of reading entire JSON files.**
|