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