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
Кредит Ханнес Landeholm для вказуючи на це