PostgreSQL | Агрегация JSONB-объектов в один объект

PostgreSQL | Агрегация JSONB-объектов в один объект

У нас есть столбец из JSONB объектов. Нам нужно соединить все объекты этого столбца в один JSONB объект с общим набором свойств (пар «ключ/значение»).

Наш идеальный сценарий — все ключи в объектах будут уникальными. Просто подходит под задачу по «сливу» всех ключей в один JSONB объект.

Решение:

-- explain analyze
select
  jsonb_object_agg(
    (select (jsonb_each(obj)).key), (select (jsonb_each(obj)).value::numeric)
  )
from (
  select '{"a": 11}'::jsonb as obj
  union select '{"b": 22}'::jsonb
  union select '{"c": 33}'::jsonb
) as T;
-- {"a": 11, "b": 22, "c": 33}

Мы имитируем таблицу через «union» с несколькими запросами.

Каждый JSONB объект мы приводим к типу «record» при помощи функции «jsonb_each«. Обращение к ключу в record будет иметь вид «.key«. Обращение к значению в record будет иметь вид «.value«.

Ключ автоматически имеет SQL-тип «text», что соответствует типу «string» по стандарту ECMAScript. Значения в свойствах нужно приводить к желаемому типу — в нашем случае это «numeric».

Упаковку пар «ключ/значение» берёт на себя агрегатная функция «jsonb_object_agg«, которой нужно для работы два SQL-столбца таблицы. Она сама понимает какой столбец первый(с ключами), а какой второй(со значениями).

Чтобы не ловить ошибку вида «ERROR: aggregate function calls cannot contain set-returning function calls», нужно дописать «select» перед выражениями «(jsonb_each(obj)).key» и «(jsonb_each(obj)).value::numeric» и обернуть круглыми скобками для имитации вызова анонимной функции (анонимного вычисления).

Итоговый оJSONB объект будет иметь вид {«a»: 11, «b»: 22, «c»: 33}