PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL-Ergebnissatz als JSON-Array zurückgeben?

TL;DR

SELECT json_agg(t) FROM t

für ein JSON-Array von Objekten und

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

für ein JSON-Objekt von Arrays.

Liste der Objekte

In diesem Abschnitt wird beschrieben, wie Sie ein JSON-Array von Objekten generieren, wobei jede Zeile in ein einzelnes Objekt konvertiert wird. Das Ergebnis sieht so aus:

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

9.3 und höher

Der json_agg Funktion erzeugt dieses Ergebnis sofort. Es findet automatisch heraus, wie seine Eingabe in JSON konvertiert wird, und aggregiert sie in einem Array.

SELECT json_agg(t) FROM t

Es gibt kein jsonb (eingeführt in 9.4) Version von json_agg . Sie können die Zeilen entweder zu einem Array aggregieren und dann konvertieren:

SELECT to_jsonb(array_agg(t)) FROM t

oder kombinieren Sie json_agg mit Besetzung:

SELECT json_agg(t)::jsonb FROM t

Meine Tests deuten darauf hin, dass es etwas schneller ist, sie zuerst in einem Array zu aggregieren. Ich vermute, dass dies daran liegt, dass die Besetzung das gesamte JSON-Ergebnis analysieren muss.

9.2

9.2 hat nicht den json_agg oder to_json Funktionen, daher müssen Sie das ältere array_to_json verwenden :

SELECT array_to_json(array_agg(t)) FROM t

Sie können optional einen row_to_json einfügen Aufruf in der Abfrage:

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

Dadurch wird jede Zeile in ein JSON-Objekt konvertiert, die JSON-Objekte als Array aggregiert und das Array dann in ein JSON-Array konvertiert.

Ich konnte keinen signifikanten Leistungsunterschied zwischen den beiden feststellen.

Objekt von Listen

In diesem Abschnitt wird beschrieben, wie Sie ein JSON-Objekt generieren, wobei jeder Schlüssel eine Spalte in der Tabelle und jeder Wert ein Array der Werte der Spalte ist. Das Ergebnis sieht so aus:

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

9.5 und höher

Wir können das json_build_object nutzen Funktion:

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

Sie können die Spalten auch aggregieren, eine einzelne Zeile erstellen und diese dann in ein Objekt umwandeln:

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

Beachten Sie, dass das Aliasing der Arrays unbedingt erforderlich ist, um sicherzustellen, dass das Objekt die gewünschten Namen hat.

Was klarer ist, ist Ansichtssache. Bei Verwendung des json_build_object Funktion, empfehle ich dringend, ein Schlüssel/Wert-Paar in einer Zeile zu platzieren, um die Lesbarkeit zu verbessern.

Sie könnten auch array_agg verwenden anstelle von json_agg , aber mein Test zeigt, dass json_agg ist etwas schneller.

Es gibt kein jsonb Version des json_build_object Funktion. Sie können in eine einzelne Zeile aggregieren und konvertieren:

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

Im Gegensatz zu den anderen Abfragen für diese Art von Ergebnis, array_agg scheint etwas schneller zu sein, wenn to_jsonb verwendet wird . Ich vermute, dass dies auf das Overhead-Parsing und die Validierung des JSON-Ergebnisses von json_agg zurückzuführen ist .

Oder Sie können eine explizite Umwandlung verwenden:

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

Die to_jsonb Version ermöglicht es Ihnen, die Besetzung zu vermeiden und ist laut meinen Tests schneller; Auch hier vermute ich, dass dies auf den Overhead beim Parsen und Validieren des Ergebnisses zurückzuführen ist.

9.4 und 9.3

Das json_build_object Funktion war neu in 9.5, daher müssen Sie in früheren Versionen aggregieren und in ein Objekt konvertieren:

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

oder

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

je nachdem, ob Sie json möchten oder jsonb .

(9.3 hat kein jsonb .)

9.2

In 9.2 nicht einmal to_json existiert. Sie müssen row_to_json verwenden :

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

Dokumentation

Die Dokumentation für die JSON-Funktionen finden Sie unter JSON-Funktionen.

json_agg befindet sich auf der Seite mit den Aggregatfunktionen.

Gestaltung

Wenn Leistung wichtig ist, stellen Sie sicher, dass Sie Ihre Abfragen mit Ihrem eigenen Schema und Ihren eigenen Daten vergleichen, anstatt meinen Tests zu vertrauen.

Ob es sich um ein gutes Design handelt oder nicht, hängt wirklich von Ihrer spezifischen Anwendung ab. Hinsichtlich der Wartbarkeit sehe ich kein besonderes Problem. Es vereinfacht Ihren App-Code und bedeutet, dass in diesem Teil der App weniger zu warten ist. Wenn PG Ihnen genau das Ergebnis liefern kann, das Sie sofort benötigen, wäre der einzige Grund, der mir einfällt, es nicht zu verwenden, Leistungsüberlegungen. Erfinde das Rad nicht neu und so weiter.

Nullen

Aggregatfunktionen geben normalerweise NULL zurück wenn sie über null Reihen arbeiten. Wenn dies möglich ist, sollten Sie vielleicht COALESCE verwenden um sie zu vermeiden. Ein paar Beispiele:

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

Oder

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

Dank an Hannes Landeholm für den Hinweis