Ако приемем поне Postgres 9.5, това ще свърши работата:
SELECT jsonb_pretty(to_jsonb(p)) AS post_row_as_json
FROM (
SELECT id, title, author_id, c.content
FROM posts p
LEFT JOIN LATERAL (
SELECT jsonb_agg(
CASE WHEN c.elem->>'type' = 'image' AND i.id IS NOT NULL
THEN elem - 'image_id' || jsonb_build_object('image', i)
ELSE c.elem END) AS content
FROM jsonb_array_elements(p.content) AS c(elem)
LEFT JOIN images i ON c.elem->>'type' = 'image'
AND i.id = (elem->>'image_id')::uuid
) c ON true
) p;
Как?
-
Премахнете
jsonb
масив, произвеждащ 1 ред на елемент от масива:jsonb_array_elements(p.content) AS c(elem)
-
За всеки елемент
LEFT JOIN
къмimages
при условията, които
а. Ключът 'type' има стойността 'image':c.elem->>'type' = 'image'
б. UUID вimage_id
съвпада с:i.id = (elem->>'image_id')::uuid
-
За типове изображения, където е намерено съответстващо изображение
c.elem->>'type' = 'image' AND i.id IS NOT NULL
премахнете ключа 'image_id' и добавете свързания ред с изображение като
jsonb
стойност:elem - 'image_id' || jsonb_build_object('image', i)
В противен случай запазете оригиналния елемент.
-
Реагрегирайте модифицираните елементи в ново
content
колона сjsonb_agg()
. -
Безусловно
LEFT JOIN LATERAL
резултатът къмposts
и изберете всички колони, заменете самоp.content
с генерирания заместителc.content
-
Във външния
SELECT
, конвертирайте целия ред вjsonb
с простto_jsonb()
.
Всички jsonb
функциите са документирани в ръководството тук.