TL;DR
SELECT json_agg(t) FROM t
за JSON масив от обекти и
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
за JSON обект от масиви.
Списък с обекти
Този раздел описва как да генерирате JSON масив от обекти, като всеки ред се преобразува в един обект. Резултатът изглежда така:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 и по-нови версии
json_agg
функция произвежда този резултат извън кутията. Той автоматично разбира как да преобразува входа си в JSON и го агрегира в масив.
SELECT json_agg(t) FROM t
Няма jsonb
(въведена в 9.4) версия на json_agg
. Можете или да агрегирате редовете в масив и след това да ги конвертирате:
SELECT to_jsonb(array_agg(t)) FROM t
или комбинирайте json_agg
с отливка:
SELECT json_agg(t)::jsonb FROM t
Моето тестване предполага, че агрегирането им в масив първо е малко по-бързо. Подозирам, че това е така, защото предаването трябва да анализира целия JSON резултат.
9.2
9.2 няма json_agg
или to_json
функции, така че трябва да използвате по-стария array_to_json
:
SELECT array_to_json(array_agg(t)) FROM t
По желание можете да включите row_to_json
обадете се в заявката:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Това преобразува всеки ред в JSON обект, агрегира JSON обектите като масив и след това преобразува масива в JSON масив.
Не успях да открия някаква значителна разлика в производителността между двете.
Обект на списъци
Този раздел описва как да генерирате JSON обект, като всеки ключ е колона в таблицата и всяка стойност е масив от стойностите на колоната. Това е резултатът, който изглежда така:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5 и нагоре
Можем да използваме json_build_object
функция:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Можете също така да агрегирате колоните, създавайки един ред и след това да го конвертирате в обект:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Имайте предвид, че псевдонимът на масивите е абсолютно необходим, за да се гарантира, че обектът има желаните имена.
Кое е по-ясно е въпрос на мнение. Ако използвате json_build_object
функция, силно препоръчвам да поставите една двойка ключ/стойност на ред, за да подобрите четливостта.
Можете също да използвате array_agg
на мястото на json_agg
, но моето тестване показва, че json_agg
е малко по-бързо.
Няма jsonb
версия на json_build_object
функция. Можете да агрегирате в един ред и да конвертирате:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
За разлика от другите заявки за този вид резултати, array_agg
изглежда е малко по-бърз при използване на to_jsonb
. Подозирам, че това се дължи на главен анализ и валидиране на JSON резултата от json_agg
.
Или можете да използвате изрично прехвърляне:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
to_jsonb
версията ви позволява да избягвате прехвърлянето и е по-бърза, според моето тестване; отново подозирам, че това се дължи на излишни разходи при анализиране и валидиране на резултата.
9.4 и 9.3
json_build_object
функцията беше нова за 9.5, така че трябва да агрегирате и конвертирате в обект в предишни версии:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
или
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
в зависимост от това дали искате json
или jsonb
.
(9.3 няма jsonb
.)
9.2
В 9.2 дори не to_json
съществува. Трябва да използвате 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
Документация
Намерете документацията за функциите JSON във функциите на JSON.
json_agg
е на страницата с обобщени функции.
Дизайн
Ако производителността е важна, уверете се, че сравнявате заявките си с вашата собствена схема и данни, вместо да се доверявате на моето тестване.
Дали е добър дизайн или не зависи от конкретното ви приложение. По отношение на поддръжката не виждам особен проблем. Това опростява кода на приложението ви и означава, че има по-малко за поддържане в тази част от приложението. Ако PG може да ви даде точно желания резултат от кутията, единствената причина, която се сещам да не го използвам, е съображенията за производителност. Не изобретявайте колелото и всичко останало.
Нули
Агрегатните функции обикновено връщат NULL
когато работят над нула редове. Ако това е възможно, може да искате да използвате COALESCE
за да ги избягвам. Няколко примера:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Или
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Кредит на Ханес Ландехолм, че посочи това