PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL restituisce il set di risultati come array JSON?

TL;DR

SELECT json_agg(t) FROM t

per una matrice JSON di oggetti e

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

per un oggetto JSON di array.

Elenco oggetti

Questa sezione descrive come generare una matrice JSON di oggetti, con ogni riga convertita in un singolo oggetto. Il risultato è simile al seguente:

[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]

9.3 e versioni successive

Il json_agg la funzione produce questo risultato fuori dagli schemi. Capisce automaticamente come convertire il suo input in JSON e lo aggrega in un array.

SELECT json_agg(t) FROM t

Non ci sono jsonb (introdotta nella versione 9.4) di json_agg . Puoi aggregare le righe in un array e poi convertirle:

SELECT to_jsonb(array_agg(t)) FROM t

oppure combina json_agg con un calco:

SELECT json_agg(t)::jsonb FROM t

I miei test suggeriscono che aggregarli prima in un array è un po' più veloce. Sospetto che ciò sia dovuto al fatto che il cast deve analizzare l'intero risultato JSON.

9.2

9.2 non ha il json_agg o to_json funzioni, quindi è necessario utilizzare il vecchio array_to_json :

SELECT array_to_json(array_agg(t)) FROM t

Puoi opzionalmente includere un row_to_json chiama nella query:

SELECT array_to_json(array_agg(row_to_json(t))) FROM t

Questo converte ogni riga in un oggetto JSON, aggrega gli oggetti JSON come un array e quindi converte l'array in un array JSON.

Non sono riuscito a distinguere alcuna differenza significativa di prestazioni tra i due.

Oggetto delle liste

Questa sezione descrive come generare un oggetto JSON, in cui ogni chiave è una colonna nella tabella e ogni valore è una matrice dei valori della colonna. È il risultato che assomiglia a questo:

{"a":[1,2,3], "b":["value1","value2","value3"]}

9.5 e versioni successive

Possiamo sfruttare json_build_object funzione:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

Puoi anche aggregare le colonne, creando una singola riga, e poi convertirla in un oggetto:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

Nota che l'aliasing degli array è assolutamente necessario per garantire che l'oggetto abbia i nomi desiderati.

Quale sia più chiaro è una questione di opinione. Se si utilizza json_build_object funzione, consiglio vivamente di inserire una coppia chiave/valore su una riga per migliorare la leggibilità.

Puoi anche usare array_agg al posto di json_agg , ma il mio test indica che json_agg è leggermente più veloce.

Non ci sono jsonb versione del json_build_object funzione. Puoi aggregare in una singola riga e convertire:

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

A differenza delle altre query per questo tipo di risultato, array_agg sembra essere un po' più veloce quando si usa to_jsonb . Sospetto che ciò sia dovuto all'analisi dell'overhead e alla convalida del risultato JSON di json_agg .

Oppure puoi utilizzare un cast esplicito:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )::jsonb
FROM t

Il to_jsonb la versione permette di evitare il cast ed è più veloce, secondo i miei test; ancora una volta, sospetto che ciò sia dovuto al sovraccarico dell'analisi e della convalida del risultato.

9.4 e 9.3

Il json_build_object la funzione era nuova alla 9.5, quindi è necessario aggregare e convertire in un oggetto nelle versioni precedenti:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

o

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

a seconda che tu voglia json o jsonb .

(9.3 non ha jsonb .)

9.2

In 9.2, nemmeno to_json esiste. Devi usare 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

Documentazione

Trova la documentazione per le funzioni JSON nelle funzioni JSON.

json_agg si trova nella pagina delle funzioni aggregate.

Progettazione

Se le prestazioni sono importanti, assicurati di confrontare le tue query con il tuo schema e i tuoi dati, piuttosto che fidarti dei miei test.

Che si tratti di un buon design o meno, dipende davvero dalla tua applicazione specifica. In termini di manutenibilità, non vedo alcun problema particolare. Semplifica il codice dell'app e significa che c'è meno da mantenere in quella parte dell'app. Se PG può darti esattamente il risultato di cui hai bisogno, l'unico motivo per cui mi viene in mente di non usarlo sarebbe considerazioni sulle prestazioni. Non reinventare la ruota e tutto il resto.

Nulli

Le funzioni aggregate in genere restituiscono NULL quando operano su zero righe. Se questa è una possibilità, potresti voler usare COALESCE per evitarli. Un paio di esempi:

SELECT COALESCE(json_agg(t), '[]'::json) FROM t

Oppure

SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t

Ringraziamento a Hannes Landeholm per averlo fatto notare