TL; DR
SELECT json_agg(t) FROM t
para uma matriz de objetos JSON e
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
para um objeto JSON de matrizes.
Lista de objetos
Esta seção descreve como gerar uma matriz de objetos JSON, com cada linha sendo convertida em um único objeto. O resultado fica assim:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 e superior
A json_agg
função produz esse resultado imediatamente. Ele automaticamente descobre como converter sua entrada em JSON e a agrega em uma matriz.
SELECT json_agg(t) FROM t
Não existe jsonb
(introduzida na 9.4) versão do json_agg
. Você pode agregar as linhas em uma matriz e depois convertê-las:
SELECT to_jsonb(array_agg(t)) FROM t
ou combine json_agg
com um elenco:
SELECT json_agg(t)::jsonb FROM t
Meus testes sugerem que agregá-los em uma matriz primeiro é um pouco mais rápido. Eu suspeito que isso ocorre porque o elenco precisa analisar o resultado JSON inteiro.
9.2
9.2 não possui as funções json_agg
ou to_json
, portanto, você precisa usar as mais antigas array_to_json
:
SELECT array_to_json(array_agg(t)) FROM t
Opcionalmente, você pode incluir uma row_to_json
chamada na consulta:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Isso converte cada linha em um objeto JSON, agrega os objetos JSON como uma matriz e, em seguida, converte a matriz em uma matriz JSON.
Não consegui discernir nenhuma diferença significativa de desempenho entre os dois.
Objeto de listas
Esta seção descreve como gerar um objeto JSON, com cada chave sendo uma coluna na tabela e cada valor sendo uma matriz dos valores da coluna. É o resultado que se parece com isso:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5 e superior
Podemos aproveitar a json_build_object
função:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Você também pode agregar as colunas, criando uma única linha e convertê-las em um objeto:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Observe que o alias das matrizes é absolutamente necessário para garantir que o objeto tenha os nomes desejados.
Qual é o mais claro é uma questão de opinião. Se estiver usando a json_build_object
função, recomendo colocar um par de chave / valor em uma linha para melhorar a legibilidade.
Você também pode usar array_agg
no lugar de json_agg
, mas meus testes indicam que json_agg
é um pouco mais rápido.
Não há jsonb
versão da json_build_object
função. Você pode agregar em uma única linha e converter:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Ao contrário das outras consultas para esse tipo de resultado, array_agg
parece ser um pouco mais rápido ao usar to_jsonb
. Eu suspeito que isso se deva à sobrecarga de análise e validação do resultado JSON de json_agg
.
Ou você pode usar um elenco explícito:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
A to_jsonb
versão permite evitar o elenco e é mais rápida, de acordo com meus testes; novamente, suspeito que isso se deva à sobrecarga de analisar e validar o resultado.
9.4 e 9.3
A json_build_object
função era nova na 9.5, portanto, você precisa agregar e converter em um objeto nas versões anteriores:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
ou
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
dependendo se você deseja json
ou jsonb
.
(9.3 não possui jsonb
.)
9.2
No 9.2, nem to_json
existe. Você deve usar row_to_json
:
SELECT row_to_json(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Documentação
Encontre a documentação para as funções JSON nas funções JSON .
json_agg
está na página de funções agregadas .
Projeto
Se o desempenho for importante, verifique se suas consultas são comparadas com seu próprio esquema e dados, em vez de confiar nos meus testes.
Se é um bom design ou não, realmente depende da sua aplicação específica. Em termos de manutenção, não vejo nenhum problema específico. Isso simplifica o código do seu aplicativo e significa que há menos para manter nessa parte do aplicativo. Se o PG pode fornecer exatamente o resultado que você precisa imediatamente, a única razão pela qual posso pensar em não usá-lo seria considerações de desempenho. Não reinvente a roda e tudo.
Nulos
As funções agregadas geralmente retornam NULL
quando operam sobre zero linhas. Se isso for uma possibilidade, convém usá-lo COALESCE
para evitá-los. Alguns exemplos:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Ou
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Agradecemos a Hannes Landeholm por apontar isso