sql >> Database >  >> RDS >> PostgreSQL

Retourresultaat van PostgreSQL als JSON-array?

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



  1. Dilemma tabelnaamgeving:enkelvoud versus meervoudsnamen

  2. Gids voor het ontwerpen van een database voor kalendergebeurtenissen en herinneringen in MySQL

  3. Java - Hoe roep ik een orakelprocedure aan met aangepaste typen?

  4. TOON TABELLEN in MariaDB