JSON Toolkit

JMESPath para iniciantes: consultas de projeção que batem o JSONPath

Resumo: JMESPath remodela lotes de objetos de forma mais direta que o JSONPath. Este guia para iniciantes cobre sintaxe, projeções, pipes, funções embutidas e uso no AWS CLI.

Iniciante~9 min de leituraPublicado em 2026-10-31Atualizado em 2026-10-31
Capa de JMESPath para iniciantes

Resumo da ópera: use JSON Pointer para localizar por posição, JSONPath para filtrar ou descer recursivamente, e JMESPath quando precisar remodelar o resultado ou projetá-lo na linha de comando; um único campo conhecido não precisa de nenhum deles.

Se seu objetivo é remodelar um lote de objetos em uma forma diferente, o JMESPath normalmente é mais direto que o JSONPath. Ele não procura nós; ele constrói um resultado.

1. O que é JMESPath

JMESPath é uma linguagem de consulta projetada especificamente para JSON. Foi originalmente criada para filtrar a saída do AWS CLI e depois se espalhou por muitas linguagens por meio de implementações como jmespath.js, jmespath.py e go-jmespath. Seu objetivo difere do JSONPath:

  • JSONPath foca em selecionar um conjunto de nós por caminho e condição, e retorna um conjunto de nós;
  • JMESPath foca em transformar o JSON de entrada e retorna um valor de qualquer forma.

Essa diferença torna o JMESPath especialmente bom em projeções de lista, renomeação de campos e corte de resultados, como reduzir vinte campos de uma resposta de API aos três campos que o frontend realmente precisa. Se você ainda não leu o básico de JSONPath, comece por A linguagem de consulta JSONPath na prática.

2. Sintaxe básica: de identificadores a índices

JMESPath usa menos símbolos que o JSONPath e se lê mais como uma expressão de extração:

Sintaxe Significado Exemplo
name Acessar um membro de objeto people
a.b Acessar membros aninhados store.bicycle.color
[0] Acessar um índice de array people[0]
[-1] Acessar o último elemento people[-1]
[0:2] Fatia, início inclusivo e fim exclusivo people[0:2]
[*] Projeção de lista people[*].name
[] Projeção de achatamento people[].tags[]
[?condition] Projeção de filtro people[?age > 18]
{key: expr} Hash de seleção múltipla {name: name, age: age}
[expr, expr] Lista de seleção múltipla [name, age]
| Canalizar o resultado da esquerda para a direita people[*].age | [0]

Um exemplo mínimo:

{
  "people": [
    { "name": "Alice", "age": 31, "city": "Shanghai" },
    { "name": "Bob", "age": 17, "city": "Beijing" }
  ]
}
people[0].name      → "Alice"
people[-1].city     → "Beijing"
people[0:2].name    → ["Alice", "Bob"]

Observe por que people[0:2].name retorna um array: uma fatia retorna uma lista, e o .name seguinte é automaticamente projetado sobre cada elemento dessa lista. Essa é a maior diferença entre JMESPath e acesso comum a objeto.

3. Projeções: transformando uma lista em outra

Uma projeção é o conceito central em JMESPath. Funciona em duas etapas: avalia cada elemento de uma lista e depois coleta os resultados em uma nova lista. Elementos que avaliam para null são descartados automaticamente.

people[*].name                   // ["Alice", "Bob"]
people[*].{name: name, age: age} // uma lista de objetos
people[?age > 18].name           // ["Alice"]

A segunda linha é uma expressão de projeção típica: people[*].{name: name, age: age}. Ela reconstrói cada elemento como { "name": ..., "age": ... } e descarta o campo extra city. Comparado ao JSONPath, que lhe dá nós para depois mapear no código, isso economiza um laço.

Vale distinguir dois tipos de projeção:

  • [*] preserva a estrutura original da lista e pula valores nulos;
  • [] é uma projeção de achatamento que primeiro colapsa um nível de listas aninhadas, o que convém a expressões como people[].tags[] que precisam de "todas as tags de todas as pessoas".

4. Pipes e seleção múltipla

O pipe | significa "pare a projeção atual e trate o resultado como uma nova entrada". Seu uso mais comum é pegar um índice após uma projeção:

people[*].name | [0]           → "Alice"
people[*].age | sort(@) | [-1] → a idade máxima

Sem o pipe, people[*].name[0] é interpretado como pegar o primeiro caractere de cada nome, o que não é o que você quer. O pipe é o símbolo mais facilmente negligenciado e mais útil do JMESPath.

Há duas formas de seleção múltipla:

// Hash de seleção múltipla: o resultado é um objeto
people[0].{name: name, age: age}

// Lista de seleção múltipla: o resultado é um array
people[0].[name, age]

Hashes de seleção múltipla são bons para construir resultados nomeados, enquanto listas de seleção múltipla são boas para consumo posicional. Ambos podem ser aninhados dentro de projeções, mas note: em um hash de seleção múltipla, uma chave cujo valor é null ainda é mantida, enquanto uma projeção descarta o elemento null inteiro.

5. Funções embutidas

O padrão JMESPath define um conjunto de funções. As comuns incluem:

Função Finalidade Exemplo
length() Obter o comprimento length(people)
sort() Ordenar valores sort(people[*].age)
sort_by() Ordenar por um campo sort_by(people, &age)
max() / min() Máximo / mínimo max(people[*].age)
sum() Somar valores sum(people[*].age)
keys() Obter chaves de objeto keys(people[0])
contains() Verificar contenção contains(name, "Ali")
to_string() Converter para string to_string(age)

O segundo argumento de sort_by é uma expressão &, que significa "tome este campo de cada elemento":

sort_by(people, &age)[*].name

Essas funções permitem que o JMESPath faça agregação simples, enquanto o JSONPath é projetado apenas para seleção; somar e agrupar normalmente exigem jq ou código.

6. Uma comparação lado a lado com JSONPath

Dimensão JSONPath JMESPath
Objetivo principal Selecionar nós Transformar dados
Símbolo raiz $ Nenhum; escreva nomes de campo diretamente
Nó atual @ @ (apenas em argumentos de função)
Filtro [?(@.age > 18)] [?age > 18]
Wildcard [*] [*] ou []
Construir novos objetos Não suportado {name: name}
Pipes Não suportado |
Padrão RFC 9535 JMESPath Specification

Um guia de decisão em uma frase:

  • Use JSONPath quando você só precisa encontrar nós que correspondem a uma condição;
  • Use JMESPath quando precisar remodelar o resultado no que o frontend espera;
  • Não use nenhum dos dois quando estiver lendo um único campo conhecido; apenas acesse a propriedade diretamente.

Se o resultado da consulta precisa ser gravado de volta no documento, nenhuma das linguagens serve. Use JSON Pointer e patches; veja JSON Pointer, Patch e Merge Patch.

7. JMESPath no AWS CLI

O parâmetro --query do AWS CLI é JMESPath, que é seu caso de uso mais difundido:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{Id: InstanceId, State: State.Name, Type: InstanceType}' \
  --output table

Este comando faz três coisas: achata duas listas aninhadas com [], mantém apenas três campos com um hash de seleção múltipla e renderiza o resultado como tabela com --output table. Com JSONPath você precisaria de mais níveis e não obteria o efeito de "renomear mais cortar".

Outras formas comuns:

# Apenas instâncias em execução
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,PublicIpAddress]'

# O valor da tag Name
aws ec2 describe-instances --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value[]'

Observe que crases delimitam literais, não strings. No AWS CLI, strings usam aspas simples e literais JSON usam crases. Essa diferença é um dos erros de iniciante mais comuns.

8. Erros comuns

  • Confundir [*] e []: o primeiro preserva o aninhamento, o segundo achata um nível, e as estruturas resultantes são completamente diferentes;
  • Esquecer o pipe: people[*].name[0] pega o primeiro caractere de cada nome, não o primeiro nome;
  • Escrever @ dentro de um filtro: filtros JMESPath usam nomes de campo diretamente, então [?@.age > 18] está errado;
  • Tratar null como string vazia: projeções descartam null, mas hashes de seleção múltipla mantêm a chave;
  • Usar aspas duplas em literais no AWS CLI: o shell as expande primeiro e reescreve a expressão.

Conselho de depuração: valide uma expressão na menor entrada possível antes de aplicá-la a dados reais, e acrescente --output json no AWS CLI para ver resultados crus. Para edição e formatação JSON do dia a dia, combinar com Editores JSON e ferramentas de linha de comando torna a localização de caminhos de campo muito mais rápida.

Perguntas frequentes

JMESPath e JSONPath podem ser usados juntos?

Sim, mas normalmente é desnecessário. Uma abordagem comum é cortar um objeto pequeno com JMESPath e depois usar acesso simples a propriedade no código. Se você realmente precisa localizar por caminho e depois modificar, o JSONPath lê e o JSON Pointer grava, o que é uma divisão de trabalho mais clara.

Por que people[*].name retorna algo diferente de uma string única?

Porque [*] é uma projeção, e o resultado é sempre uma lista, mesmo quando há apenas uma pessoa. Para obter um valor único, acrescente um pipe e um índice: people[*].name | [0].

O que acontece com null dentro de uma projeção?

Uma projeção de lista pula automaticamente elementos que avaliam para null, então o resultado pode ser mais curto que a lista original. Um hash de seleção múltipla mantém a chave e preserva o valor null, o que importa ao construir respostas de API.

JMESPath consegue fazer agregação e agrupamento?

Consegue fazer agregação básica com sum(), max() e sort_by(). Agrupamento, joins e funções de janela estão fora do padrão. Deixe análise complexa para jq, SQL ou código.

Como decido entre JMESPath e JSONPath?

Use JSONPath quando precisar selecionar nós por caminho e condição e receber um conjunto de nós; use JMESPath quando precisar remodelar o resultado no que o frontend espera, com renomeação e corte de campos. Quando estiver lendo um único campo conhecido, não use nenhum dos dois; apenas acesse a propriedade.

Devo usar um pipe para pegar o primeiro valor projetado?

Sim. people[*].name é uma projeção, então o resultado é sempre uma lista; sem um pipe, people[*].name[0] pega o primeiro caractere de cada nome. Escreva people[*].name | [0] para obter o primeiro valor.