JSONPath e jq
Aula 3 de 4
JSONPath — Consultas em JSON
JSONPath é uma linguagem de consulta para navegar e extrair dados de documentos JSON, similar ao XPath para XML.
Expressões Básicas
| Expressão | Descrição |
|---|---|
$.usuarios | Navega para a chave usuarios |
$..nome | Busca recursiva por nome |
$.usuarios[0] | Primeiro elemento do array |
$.usuarios[*].nome | Nomes de todos os usuários |
$[?(@.idade > 30)] | Filtro condicional |
$[?(@.tags[*] == 'admin')] | Filtro por array interno |
Exemplos Práticos
{
"loja": "Tech Store",
"produtos": [
{
"nome": "Notebook",
"preco": 3500,
"categoria": "Eletrônicos",
"tags": ["promocao", "destaque"]
},
{
"nome": "Mouse",
"preco": 50,
"categoria": "Periféricos",
"tags": ["novo"]
},
{
"nome": "Monitor",
"preco": 1500,
"categoria": "Eletrônicos",
"tags": ["destaque"]
}
]
}
# Navegação básica
$.produtos[*].nome
# Resultado: ["Notebook", "Mouse", "Monitor"]
# Filtro por preço
$.produtos[?(@.preco > 1000)].nome
# Resultado: ["Notebook", "Monitor"]
# Busca recursiva
$..nome
# Resultado: ["Tech Store", "Notebook", "Mouse", "Monitor"]
jq — Processador JSON para CLI
jq é uma ferramenta de linha de comando poderosa para processar JSON.
Filtros Básicos
# Extrair campos
cat dados.json | jq '.produtos[].nome'
# Objeto formatado
cat dados.json | jq '{nome: .produtos[].nome, preco: .produtos[].preco}'
# Selecionar itens
cat dados.json | jq '.produtos[] | select(.preco > 100)'
# Array de campos específicos
cat dados.json | jq '[.produtos[] | {nome, preco}]'
Pipe e Transformações
# Pipeline de transformação
curl -s https://api.github.com/repos/stedolan/jq/commits | \
jq '[.[] | {sha: .sha[0:7], autor: .commit.author.name, msg: .commit.message | split("\n")[0]}]'
# Agregações
jq '{total: [.produtos[].preco] | add, media: [.produtos[].preco] | avg, max: [.produtos[].preco] | max}' dados.json
# Map e Select
cat dados.json | jq '.produtos | map(select(.preco > 100)) | map(.nome)'
Manipulação em Pipelines Bash
# Extrair API JSON e processar
curl -s "https://api.github.com/repos/jqlang/jq/issues?state=open" | \
jq 'group_by(.labels[].name) | map({label: .[0].labels[0].name, count: length})'
# Transformar JSON para CSV
curl -s "https://api.exemplo.com/usuarios" | \
jq -r '.[] | [.id, .nome, .email] | @csv' > usuarios.csv
# Atualizar valores em JSON
cat config.json | jq '.database.host = "db-novo.exemplo.com" | .database.port = 5432' > config-novo.json
# Merge de arquivos JSON
jq -s '{usuario: .[0], config: .[1]}' usuario.json config.json
# JSON pretty-print
curl -s https://api.exemplo.com/dados | jq .
Lab: Pipeline de Dados com jq
# 1. Arquivo de dados
cat << 'EOF' > vendas.json
{
"periodo": "2024-Q1",
"vendas": [
{"vendedor": "Ana", "valor": 15000, "mes": "janeiro", "regiao": "SP"},
{"vendedor": "Carlos", "valor": 22000, "mes": "janeiro", "regiao": "RJ"},
{"vendedor": "Ana", "valor": 18000, "mes": "fevereiro", "regiao": "SP"},
{"vendedor": "Beatriz", "valor": 12000, "mes": "fevereiro", "regiao": "MG"},
{"vendedor": "Carlos", "valor": 25000, "mes": "marco", "regiao": "RJ"},
{"vendedor": "Ana", "valor": 20000, "mes": "marco", "regiao": "SP"}
]
}
EOF
# 2. Análises com jq
echo "=== Total por vendedor ==="
jq '[.vendas[] | {vendedor, valor}] | group_by(.vendedor) | map({vendedor: .[0].vendedor, total: [.[].valor] | add})' vendas.json
echo ""
echo "=== Total por região ==="
jq '[.vendas[] | {regiao, valor}] | group_by(.regiao) | map({regiao: .[0].regiao, total: [.[].valor] | add})' vendas.json
echo ""
echo "=== Vendedor do mês (maior venda única) ==="
jq '.vendas | max_by(.valor) | {vendedor, valor, mes}' vendas.json
echo ""
echo "=== Média de vendas ==="
jq '[.vendas[].valor] | avg' vendas.json
echo ""
echo "=== Exportar CSV ==="
jq -r '.vendas[] | [.vendedor, .valor | tostring, .mes, .regiao] | @csv' vendas.json
# 3. JSONPath com Python
python -c "
import json
from jsonpath_ng import parse
with open('vendas.json') as f:
dados = json.load(f)
# Parse JSONPath expression
expr = parse('\$.vendas[?(@.regiao == \"SP\")].vendedor')
matches = [m.value for m in expr.find(dados)]
print(f'Vendedores de SP: {matches}')
expr = parse('\$.vendas[?(@.valor > 15000)].vendedor')
matches = [m.value for m in expr.find(dados)]
print(f'Vendas > 15000: {matches}')
"
jq transforma o terminal em um poderoso ambiente ETL para JSON — sem precisar de Python ou JavaScript.