TL;DR
SELECT json_agg(t) FROM t
pro pole objektů JSON a
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
pro objekt JSON z polí.
Seznam objektů
Tato část popisuje, jak vygenerovat pole JSON objektů, přičemž každý řádek se převede na jeden objekt. Výsledek vypadá takto:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 a vyšší
json_agg
funkce vytváří tento výsledek ihned po vybalení. Automaticky zjistí, jak převést svůj vstup na JSON, a agreguje ho do pole.
SELECT json_agg(t) FROM t
Neexistuje žádný jsonb
(zavedené v 9.4) verzi json_agg
. Řádky můžete buď agregovat do pole a poté je převést:
SELECT to_jsonb(array_agg(t)) FROM t
nebo zkombinujte json_agg
s obsazením:
SELECT json_agg(t)::jsonb FROM t
Moje testování naznačuje, že nejprve je agregovat do pole je trochu rychlejší. Mám podezření, že je to proto, že obsazení musí analyzovat celý výsledek JSON.
9.2
9.2 nemá json_agg
nebo to_json
funkce, takže musíte použít starší array_to_json
:
SELECT array_to_json(array_agg(t)) FROM t
Volitelně můžete zahrnout row_to_json
zavolejte v dotazu:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
To převede každý řádek na objekt JSON, agreguje objekty JSON jako pole a poté pole převede na pole JSON.
Nebyl jsem schopen rozeznat žádný významný rozdíl ve výkonu mezi těmito dvěma.
Objekt seznamů
Tato část popisuje, jak vygenerovat objekt JSON, přičemž každý klíč je sloupec v tabulce a každá hodnota je polem hodnot sloupce. Výsledek vypadá takto:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9,5 a vyšší
Můžeme využít json_build_object
funkce:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Můžete také agregovat sloupce, vytvořit jeden řádek a ten pak převést na objekt:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Všimněte si, že alias polí je absolutně nezbytný k zajištění toho, že objekt má požadovaná jména.
Která je jasnější, je věcí názoru. Pokud používáte json_build_object
Velmi doporučuji umístit jeden pár klíč/hodnota na řádek, aby se zlepšila čitelnost.
Můžete také použít array_agg
místo json_agg
, ale mé testování ukazuje, že json_agg
je o něco rychlejší.
Neexistuje žádný jsonb
verzi json_build_object
funkce. Můžete agregovat do jednoho řádku a převést:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Na rozdíl od ostatních dotazů pro tento druh výsledku array_agg
se zdá být trochu rychlejší při použití to_jsonb
. Mám podezření, že je to způsobeno režijní analýzou a ověřováním výsledku JSON json_agg
.
Nebo můžete použít explicitní obsazení:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
to_jsonb
verze vám umožňuje vyhnout se obsazení a je rychlejší, podle mého testování; znovu se domnívám, že je to kvůli režii analýzy a ověřování výsledku.
9.4 a 9.3
json_build_object
funkce byla ve verzi 9.5 nová, takže v předchozích verzích musíte agregovat a převést na objekt:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
nebo
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
podle toho, zda chcete json
nebo jsonb
.
(9.3 nemá jsonb
.)
9.2
Ve verzi 9.2 dokonce ani to_json
existuje. Musíte použít 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
Dokumentace
Najděte dokumentaci pro funkce JSON ve funkcích JSON.
json_agg
je na stránce souhrnných funkcí.
Design
Pokud je důležitý výkon, ujistěte se, že srovnáváte své dotazy se svým vlastním schématem a daty, spíše než důvěřujte mému testování.
Zda je to dobrý design nebo ne, opravdu záleží na vaší konkrétní aplikaci. Co se týče udržovatelnosti, nevidím žádný zvláštní problém. Zjednodušuje kód vaší aplikace a znamená, že v této části aplikace je potřeba méně údržby. Pokud vám PG může po vybalení poskytnout přesně ten výsledek, který potřebujete, jediný důvod, proč jej nepoužít, mě napadá, jsou úvahy o výkonu. Neobjevujte znovu kolo a všechno.
Nulové
Agregační funkce obvykle vrátí NULL
když pracují přes nula řádků. Pokud je to možné, možná budete chtít použít COALESCE
abychom se jim vyhnuli. Pár příkladů:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Nebo
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Poděkování Hannesu Landeholmovi za to, že na to upozornil