В функции 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
это на месте?