sqlpostgresqljsonjsonb

JSONB_OBJECT_KEYS no PostgreSQL: listar as chaves de um objeto JSON como linhas

Expanda as chaves de nivel superior de um objeto JSONB em linhas, descubra o formato dos dados, verifique quais campos existem e reuna chaves com array_agg.

3 min de leituraReferencesql · postgresql · json · jsonb · schema

jsonb_object_keys e uma funcao que retorna um conjunto: emite uma linha para cada chave de nivel superior de um objeto JSON. Ela e indispensavel quando os dados sao semiestruturados e voce nao sabe de antemao quais campos existem em uma coluna. Com ela voce explora o formato do JSON, verifica se os campos esperados estao presentes e monta um inventario de chaves de uma tabela inteira.

Sintaxe e exemplo basico

A assinatura e simples: jsonb_object_keys(jsonb). Como retorna um conjunto, ela produz linhas em vez de um unico escalar. Suponha que users ganhou uma coluna prefs jsonb com as configuracoes do perfil.

SELECT jsonb_object_keys(prefs) AS key
FROM users
WHERE id = 42;

Se prefs for {"theme": "dark", "lang": "en", "newsletter": true}, a consulta retorna tres linhas: theme, lang, newsletter. Alguns comportamentos que vale conhecer:

  • Apenas as chaves de nivel superior sao retornadas. Objetos aninhados nao sao desdobrados.
  • A ordem das chaves nao e garantida; o jsonb mantem sua propria ordem interna.
  • Para algo que nao seja um objeto (array, numero, string) voce obtem zero linhas ou um erro; passe apenas objetos.
  • Existe a variante json_object_keys para o tipo json; mesmo comportamento, sem normalizacao.

Descobrir o formato dos dados

Quando uma coluna jsonb chega de uma fonte externa, a primeira pergunta e "quais chaves aparecem aqui". Desdobrar as chaves de cada linha e agrupa-las da um mapa de campos com suas frequencias.

SELECT key, COUNT(*) AS rows_with_key
FROM users u,
     jsonb_object_keys(u.prefs) AS key
GROUP BY key
ORDER BY rows_with_key DESC;

Este e o padrao canonico: uma tabela e uma funcao de conjunto no FROM formam um join LATERAL implicito, de modo que as chaves de cada usuario se expandem em linhas separadas. O resultado mostra na hora quais campos sao comuns e quais sao opcionais e raros.

Pegadinha: se prefs for NULL, a linha desse usuario simplesmente desaparece do resultado, porque a funcao nao emite nenhuma linha. Para manter esses usuarios, use um LEFT JOIN LATERAL ... ON true explicito, ou filtre WHERE prefs IS NOT NULL de forma consciente. Caso contrario, sua sondagem ignora em silencio parte da tabela.

Verificar quais campos opcionais estao presentes

jsonb_object_keys ajuda a encontrar linhas que carregam (ou nao) um campo especifico. Para uma unica verificacao o operador ? e mais pratico, mas percorrer as chaves serve para condicoes dinamicas.

-- users who configured a newsletter preference at all
SELECT id, email
FROM users
WHERE prefs ? 'newsletter';

-- equivalent shape check via the keys set
SELECT id, email
FROM users u
WHERE EXISTS (
    SELECT 1
    FROM jsonb_object_keys(u.prefs) AS key
    WHERE key = 'newsletter'
);

O operador ? (contem uma chave de nivel superior) quase sempre e mais rapido e claro para um campo, principalmente com um indice GIN em prefs. Percorrer com jsonb_object_keys se justifica quando a condicao sobre a chave nao e trivial, por exemplo "tem ao menos uma chave com prefixo flag_".

Reunir chaves com array_agg

Muitas vezes voce quer o contrario de uma expansao: uma lista compacta de chaves por linha. Combinar array_agg com uma subconsulta sobre jsonb_object_keys dobra as chaves de volta em um array.

SELECT
    u.id,
    u.email,
    (
        SELECT array_agg(key ORDER BY key)
        FROM jsonb_object_keys(u.prefs) AS key
    ) AS configured_keys
FROM users u
WHERE u.prefs IS NOT NULL;

O ORDER BY key dentro do array_agg da uma ordem estavel e legivel em vez da interna do jsonb. Esse array e facil de comparar entre linhas: encontre usuarios com um conjunto de configuracoes incomum, ou monte um relatorio de "quem tem quais campos preenchidos" sem despejar todo o JSON na aplicacao.

Outros bancos de dados

O MySQL nao tem um equivalente direto que retorne um conjunto: JSON_KEYS(prefs) devolve um array JSON de chaves como um unico valor, nao um conjunto de linhas. Para desdobra-lo voce recorre ao JSON_TABLE. No ClickHouse, a analise de JSON usa JSONExtractKeys(prefs), que tambem produz um array; expanda-o em linhas com arrayJoin. Lembre da regra comum: nos tres sistemas trata-se apenas de chaves de nivel superior, entao objetos aninhados precisam ser analisados em uma passagem separada.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador