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.
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.
SELECT id, email
FROM users
WHERE prefs ? 'newsletter';
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_".
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.
jsonb_object_keyse 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 queusersganhou uma colunaprefs jsonbcom as configuracoes do perfil.SELECT jsonb_object_keys(prefs) AS key FROM users WHERE id = 42;Se
prefsfor{"theme": "dark", "lang": "en", "newsletter": true}, a consulta retorna tres linhas:theme,lang,newsletter. Alguns comportamentos que vale conhecer:jsonbmantem sua propria ordem interna.json_object_keyspara o tipojson; mesmo comportamento, sem normalizacao.Descobrir o formato dos dados
Quando uma coluna
jsonbchega 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
FROMformam um joinLATERALimplicito, 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.Verificar quais campos opcionais estao presentes
jsonb_object_keysajuda 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 emprefs. Percorrer comjsonb_object_keysse justifica quando a condicao sobre a chave nao e trivial, por exemplo "tem ao menos uma chave com prefixoflag_".Reunir chaves com array_agg
Muitas vezes voce quer o contrario de uma expansao: uma lista compacta de chaves por linha. Combinar
array_aggcom uma subconsulta sobrejsonb_object_keysdobra 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 keydentro doarray_aggda uma ordem estavel e legivel em vez da interna dojsonb. 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 aoJSON_TABLE. No ClickHouse, a analise de JSON usaJSONExtractKeys(prefs), que tambem produz um array; expanda-o em linhas comarrayJoin. 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.