TL;DR
SELECT json_agg(t) FROM t
dla tablicy obiektów JSON i
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
dla obiektu JSON tablic.
Lista obiektów
W tej sekcji opisano sposób generowania tablicy obiektów JSON, w której każdy wiersz jest konwertowany na pojedynczy obiekt. Wynik wygląda tak:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 i nowsze
json_agg
funkcja generuje ten wynik po wyjęciu z pudełka. Automatycznie dowiaduje się, jak przekonwertować dane wejściowe do formatu JSON i agregować je w tablicę.
SELECT json_agg(t) FROM t
Nie ma jsonb
(wprowadzony w 9.4) wersja json_agg
. Możesz albo zagregować wiersze w tablicę, a następnie je przekonwertować:
SELECT to_jsonb(array_agg(t)) FROM t
lub połącz json_agg
z obsadą:
SELECT json_agg(t)::jsonb FROM t
Moje testy sugerują, że agregowanie ich najpierw w tablicę jest nieco szybsze. Podejrzewam, że dzieje się tak, ponieważ obsada musi przeanalizować cały wynik JSON.
9,2
9.2 nie ma json_agg
lub to_json
funkcje, więc musisz użyć starszego array_to_json
:
SELECT array_to_json(array_agg(t)) FROM t
Opcjonalnie możesz dołączyć row_to_json
zadzwoń w zapytaniu:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
To konwertuje każdy wiersz na obiekt JSON, agreguje obiekty JSON jako tablicę, a następnie konwertuje tablicę na tablicę JSON.
Nie byłem w stanie dostrzec żadnej znaczącej różnicy w wydajności między tymi dwoma.
Obiekt list
W tej sekcji opisano, jak wygenerować obiekt JSON, przy czym każdy klucz jest kolumną w tabeli, a każda wartość jest tablicą wartości kolumny. Wynik wygląda tak:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9,5 i więcej
Możemy wykorzystać json_build_object
funkcja:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Możesz także zagregować kolumny, tworząc pojedynczy wiersz, a następnie przekonwertować go na obiekt:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Zwróć uwagę, że aliasowanie tablic jest absolutnie wymagane, aby zapewnić, że obiekt ma żądane nazwy.
To, które z nich jest jaśniejsze, jest kwestią opinii. Jeśli używasz json_build_object
funkcji, gorąco polecam umieszczenie jednej pary klucz/wartość w linii, aby poprawić czytelność.
Możesz także użyć array_agg
zamiast json_agg
, ale moje testy wskazują, że json_agg
jest nieco szybszy.
Nie ma jsonb
wersja json_build_object
funkcjonować. Możesz zagregować w jeden wiersz i przekonwertować:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
W przeciwieństwie do innych zapytań o tego rodzaju wynik, array_agg
wydaje się być trochę szybszy przy użyciu to_jsonb
. Podejrzewam, że jest to spowodowane narzutem analizowania i weryfikowania wyniku JSON json_agg
.
Możesz też użyć wyraźnej obsady:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
to_jsonb
wersja pozwala uniknąć rzutów i jest szybsza, według moich testów; ponownie, podejrzewam, że jest to spowodowane narzutem na analizę i walidację wyniku.
9.4 i 9.3
json_build_object
funkcja była nowa w 9.5, więc musisz agregować i konwertować do obiektu w poprzednich wersjach:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
lub
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
w zależności od tego, czy chcesz json
lub jsonb
.
(9.3 nie ma jsonb
.)
9,2
W wersji 9.2 nawet to_json
istnieje. Musisz użyć 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
Dokumentacja
Znajdź dokumentację funkcji JSON w funkcjach JSON.
json_agg
znajduje się na stronie funkcji agregujących.
Projekt
Jeśli wydajność jest ważna, upewnij się, że porównałeś swoje zapytania z własnym schematem i danymi, zamiast ufać moim testom.
To, czy projekt jest dobry, czy nie, zależy od konkretnego zastosowania. Jeśli chodzi o łatwość utrzymania, nie widzę żadnego szczególnego problemu. Upraszcza to kod aplikacji i oznacza, że w tej części aplikacji jest mniej do utrzymania. Jeśli PG może dać ci dokładnie taki wynik, jakiego potrzebujesz po wyjęciu z pudełka, jedynym powodem, dla którego mogę go nie używać, są względy wydajności. Nie wymyślaj koła na nowo i w ogóle.
Null
Funkcje agregujące zazwyczaj zwracają NULL
kiedy operują na zerowych rzędach. Jeśli jest taka możliwość, możesz użyć COALESCE
aby ich uniknąć. Kilka przykładów:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Lub
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Podziękowanie dla Hannesa Landeholma za wskazanie tego