TL;DR
SELECT json_agg(t) FROM t
para uma matriz JSON de objetos 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 JSON de objetos, 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
O
json_agg função produz esse resultado fora da caixa. Ele descobre automaticamente como converter sua entrada em JSON e a agrega em uma matriz. SELECT json_agg(t) FROM t
Não há
jsonb (introduzido em 9.4) versão de 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 elenco:SELECT json_agg(t)::jsonb FROM t
Meus testes sugerem que agregá-los em um array primeiro é um pouco mais rápido. Suspeito que isso ocorra porque o elenco precisa analisar todo o resultado JSON.
9.2
9.2 não tem o
json_agg ou to_json funções, então você precisa usar o antigo array_to_json :SELECT array_to_json(array_agg(t)) FROM t
Opcionalmente, você pode incluir um
row_to_json ligue 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 o
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 depois convertê-la 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 dos arrays é absolutamente necessário para garantir que o objeto tenha os nomes desejados.
Qual é mais claro é uma questão de opinião. Se estiver usando o
json_build_object função, eu recomendo colocar um par 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 do 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 . Suspeito que isso se deva à análise de sobrecarga e à validação do resultado JSON de json_agg . Ou você pode usar uma conversão explícita:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
O
to_jsonb versão permite que você evite o elenco e é mais rápido, de acordo com meus testes; novamente, suspeito que isso se deva à sobrecarga de análise e validação do resultado. 9,4 e 9,3
O
json_build_object função era nova para 9.5, então você tem que agregar e converter para 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 tem
jsonb .) 9.2
Em 9.2, nem mesmo
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 das funções JSON em funções JSON.
json_agg está na página de funções agregadas. Projeto
Se o desempenho for importante, certifique-se de comparar suas consultas com seu próprio esquema e dados, em vez de confiar em meus testes.
Se é um bom design ou não depende muito da sua aplicação específica. Em termos de manutenção, não vejo nenhum problema em particular. 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, a única razão que posso pensar para não usá-lo seriam considerações de desempenho. Não reinvente a roda e tudo.
Nulos
Funções agregadas normalmente devolvem
NULL quando eles operam em zero linhas. Se esta for uma possibilidade, você pode querer usar 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
Crédito a Hannes Landeholm por apontar isso