TL;DR
SELECT json_agg(t) FROM t
voor een JSON-array van objecten, en
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
voor een JSON-object van arrays.
Lijst met objecten
In deze sectie wordt beschreven hoe u een JSON-array met objecten genereert, waarbij elke rij wordt geconverteerd naar één object. Het resultaat ziet er als volgt uit:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 en hoger
De json_agg
functie produceert dit resultaat uit de doos. Het zoekt automatisch uit hoe de invoer moet worden omgezet in JSON en voegt deze samen tot een array.
SELECT json_agg(t) FROM t
Er is geen jsonb
(geïntroduceerd in 9.4) versie van json_agg
. U kunt de rijen samenvoegen tot een array en ze vervolgens converteren:
SELECT to_jsonb(array_agg(t)) FROM t
of combineer json_agg
met een cast:
SELECT json_agg(t)::jsonb FROM t
Mijn testen suggereren dat het iets sneller is om ze eerst in een array samen te voegen. Ik vermoed dat dit komt omdat de cast het volledige JSON-resultaat moet ontleden.
9.2
9.2 heeft niet de json_agg
of to_json
functies, dus u moet de oudere array_to_json
. gebruiken :
SELECT array_to_json(array_agg(t)) FROM t
U kunt optioneel een row_to_json
. toevoegen roep de vraag in:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Dit converteert elke rij naar een JSON-object, voegt de JSON-objecten samen als een array en converteert de array vervolgens naar een JSON-array.
Ik heb geen significant prestatieverschil tussen de twee kunnen ontdekken.
Object van lijsten
In deze sectie wordt beschreven hoe u een JSON-object genereert, waarbij elke sleutel een kolom in de tabel is en elke waarde een matrix van de waarden van de kolom is. Het resultaat ziet er als volgt uit:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5 en hoger
We kunnen gebruikmaken van het json_build_object
functie:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
U kunt de kolommen ook aggregeren, een enkele rij maken en die vervolgens omzetten in een object:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Merk op dat het aliasen van de arrays absoluut vereist is om ervoor te zorgen dat het object de gewenste namen heeft.
Welke duidelijker is, is een kwestie van mening. Bij gebruik van de json_build_object
functie, raad ik u ten zeerste aan om één sleutel/waarde-paar op een regel te plaatsen om de leesbaarheid te verbeteren.
U kunt ook array_agg
. gebruiken in plaats van json_agg
, maar mijn testen geven aan dat json_agg
is iets sneller.
Er is geen jsonb
versie van het json_build_object
functie. U kunt samenvoegen tot een enkele rij en het volgende converteren:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
In tegenstelling tot de andere zoekopdrachten voor dit soort resultaten, array_agg
lijkt iets sneller te zijn bij gebruik van to_jsonb
. Ik vermoed dat dit te wijten is aan het ontleden en valideren van het JSON-resultaat van json_agg
.
Of je kunt een expliciete cast gebruiken:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
De to_jsonb
versie stelt je in staat om de cast te vermijden en is sneller, volgens mijn testen; nogmaals, ik vermoed dat dit te wijten is aan de overhead van het ontleden en valideren van het resultaat.
9,4 en 9,3
Het json_build_object
functie was nieuw voor 9.5, dus je moet aggregeren en converteren naar een object in eerdere versies:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
of
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
afhankelijk van of je json
. wilt of jsonb
.
(9.3 heeft geen jsonb
.)
9.2
In 9.2, zelfs niet to_json
bestaat. U moet row_to_json
. gebruiken :
SELECT row_to_json(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Documentatie
Vind de documentatie voor de JSON-functies in JSON-functies.
json_agg
staat op de pagina met geaggregeerde functies.
Ontwerp
Als prestaties belangrijk zijn, zorg er dan voor dat u uw zoekopdrachten vergelijkt met uw eigen schema en gegevens, in plaats van te vertrouwen op mijn testen.
Of het een goed ontwerp is of niet, hangt echt af van uw specifieke toepassing. Qua onderhoud zie ik geen specifiek probleem. Het vereenvoudigt uw app-code en betekent dat er minder te onderhouden is in dat gedeelte van de app. Als PG u precies het resultaat kan geven dat u uit de doos nodig heeft, is de enige reden die ik kan bedenken om het niet te gebruiken prestatieoverwegingen. Vind het wiel niet opnieuw uit en zo.
Nullen
Geaggregeerde functies geven doorgaans NULL
terug wanneer ze over nul rijen werken. Als dit een mogelijkheid is, wil je misschien COALESCE
. gebruiken om ze te vermijden. Een paar voorbeelden:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Of
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Met dank aan Hannes Landeholm om hierop te wijzen