Om du antar minst Postgres 9.5, kommer detta att göra jobbet:
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;
Hur?
-
Ta bort
jsonb
array, producerar 1 rad per arrayelement:jsonb_array_elements(p.content) AS c(elem)
-
För varje element
LEFT JOIN
tillimages
på de villkor som
a. nyckeln 'type' har värdet 'image':c.elem->>'type' = 'image'
b. UUID iimage_id
matchar:i.id = (elem->>'image_id')::uuid
-
För bildtyper, där en matchande bild hittades
c.elem->>'type' = 'image' AND i.id IS NOT NULL
ta bort nyckeln 'image_id' och lägg till den relaterade bildraden som
jsonb
värde:elem - 'image_id' || jsonb_build_object('image', i)
Behåll annars det ursprungliga elementet.
-
Aggregera de modifierade elementen igen till ett nytt
content
kolumn medjsonb_agg()
. -
Ovillkorligt
LEFT JOIN LATERAL
resultatet tillposts
och välj alla kolumner, ersätt barap.content
med den genererade ersättningenc.content
-
I den yttre
SELECT
, konvertera hela raden tilljsonb
med en enkelto_jsonb()
.
Alla jsonb
funktioner finns dokumenterade i manualen här.