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 для указывая на это