В функции SQL у меня есть массив jsonb в формате:
[{id: 1, name: John}, {id: 2, name: Jane}]
Я хотел бы преобразовать эту структуру в один jsonb, используя идентификаторы в качестве ключей:
{
1: {id: 1, name: John},
2: {id: 2, name: Jane}
}


Вы можете разбить массив с помощью jsonb_array_elements() , а затем повторно объединить его в объект с помощью jsonb_object_agg() . Демо на db<>fiddle:
select jsonb_object_agg(_element->>'id', _element)
from my_table
cross join lateral jsonb_array_elements(my_table.jdata) as _an(_element)
group by my_table.ctid
Вы не можете использовать номер JSON в качестве ключа, поэтому я использовал приведение аксессора -> к text. Не зная вашего первичного ключа, я группирую по ctid системного столбца, потому что он всегда присутствует и уникален, но вам, вероятно, нужен реальный ПК. cross join lateral можно заменить одной запятой ,, но явный синтаксис join обычно предпочтительнее старого неявного стиля.
Если вы хотите, чтобы новым ключом был не фактический id, а индекс в этом массиве, вы можете использовать с порядковым номером, чтобы получить их:
select jsonb_object_agg(n::text, e)
from my_table
, jsonb_array_elements(jdata) with ordinality as elements(e,n)
group by my_table.ctid
То же самое, но вместо update вместо select:
update my_table set jdata=
(select jsonb_object_agg(e->>'id', e)
from jsonb_array_elements(jdata) e )
returning jsonb_pretty(jdata);
Обратите внимание, что массив jsonb всегда сохраняет свой первоначальный порядок как значимый, но полученный объект jsonb будет свободно переупорядочен PostgreSQL на основе ключей.
cross join предпочтительнее соединения запятых.
@Charlieface Я знаю, что я в меньшинстве по этой теме, отсюда и замечание в ответе. Мне нравится их краткость при работе с одной таблицей, питающей множество SRF, поэтому я не против время от времени давать случайным свидетелям воспоминания об их травме SQL в 80-х-00-х годах. :)
@Charlieface При этом я отредактировал сообщение, чтобы перевернуть повествование, и оставил ,-соединение в качестве дополнительного, во втором примере, который может использовать более короткий синтаксис для размещения дополнительных ключевых слов. Я решил, что имеет смысл открыть правильный метод и после этого упоминать только другой синтаксис.
@Charlieface: Помимо личных предпочтений и сильных мнений, запятая и CROSS JOIN — это всего лишь два разных, одинаково допустимых варианта синтаксиса, даже с слегка разными ролями. См.: dba.stackexchange.com/a/167217/3684
JSON не поддерживает числовые ключи, поэтому на самом деле это будут
"1"и"2". Вы хотитеselectтолько это илиupdateэто на месте?