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