Eu tenho uma consulta como:
SELECT a.id, a.name, json_agg(b.*) as "item"
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;
Como posso selecionar as colunas b
para não ter b.item_id
no objeto JSON?
Eu li sobre ROW
, mas ele retorna um objeto JSON como:
{"f1": "Foo", "f2": "Bar"}
Eu precisaria remapear o objeto JSON uma vez que ele fosse buscado para corresponder às chaves de coluna apropriadas. Eu gostaria de evitar isso e manter os nomes das colunas originais.
Infelizmente, não há provisão na sintaxe SQL para dizer "todas as colunas, exceto esta coluna" . Você pode atingir seu objetivo soletrando a lista restante de colunas em uma expressão do tipo linha :
Isso é abreviação para a forma mais explícita: .
ROW
(b.col1, b.col2, b.col3)
No entanto, os nomes das colunas não são preservados em expressões de tipo de linha. Você obtém nomes de chave genéricos no objeto JSON dessa maneira. Vejo 3 opções para preservar os nomes das colunas originais:
1. Transmitir para o tipo registrado
Transmitir para um tipo de linha conhecido (registrado). Um tipo é registrado para cada tabela ou exibição existente ou com uma
CREATE TYPE
instrução explícita. Você pode usar uma tabela temporária para uma solução ad-hoc (duração da sessão):2. Use uma subseleção
Use uma subseleção para construir uma tabela derivada e fazer referência à tabela como um todo . Isso também carrega nomes de coluna. É mais detalhado, mas você não precisa de um tipo registrado:
3.
json_build_object()
no Postgres 9.4 ou posteriorRelacionado:
Semelhante para
jsonb
com as respectivas funçõesjsonb_agg()
ejsonb_build_object()
.Para o Postgres 9.5 ou posterior, veja também a resposta de a_horse com uma nova variante de sintaxe mais curta: Postgres adicionou o operador menos
-
parajsonb
dizer "todas as chaves exceto esta chave" .Já o Postgres 10 "exceto várias chaves" é implementado com o mesmo operador tomando
text[]
como 2º operando - como o mlt comentado.A partir do 9.6, você pode simplesmente usar
-
para remover uma chave de um JSONB:to_jsonb(b)
converterá a linha inteira e- 'item_id'
removerá a chave com o nomeitem_id
, o resultado disso será agregado.Você pode realmente fazer isso sem agrupar, usando subconsultas
retorna
Este artigo de John Atten é muito interessante e tem mais detalhes
Você pode usar
json_build_object
assimDescobri que é melhor criar o JSON e agregá-lo. por exemplo
Observe que isso pode ser feito como uma subconsulta se você não gostar de CTEs (ou tiver problemas de desempenho por causa do uso).
Observe também que, se você for fazer muito isso, pode ser benéfico criar uma função para agrupar os pares de valores-chave para você, para que o código pareça mais limpo. Você passaria sua função (por exemplo)
'ecks', 'x'
e ela retornaria"ecks": "x"
.Se você precisar excluir várias colunas, então
Embora ainda não haja como fazer nada sobre selecionar todas as colunas, exceto um bit, mas você pode usar
json_agg(to_json(b.col_1, b.col_2, b.col_3 ...))
para obter uma matriz json de jsons cada um no formato{"col_1":"col_1 value", ...}
.Assim, a consulta seria algo como:
e retornaria linhas como:
(Estou no Postgres 9.5.3 agora e não tenho 100% de certeza de quando esse suporte foi adicionado.)