Uitgaande van ten minste Postgres 9.5, zal dit het werk doen:
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;
Hoe?
-
Unnes de
jsonb
array, waardoor 1 rij per array-element wordt geproduceerd:jsonb_array_elements(p.content) AS c(elem)
-
Voor elk element
LEFT JOIN
naarimages
op de voorwaarden die
a. De toets 'type' heeft de waarde 'image':c.elem->>'type' = 'image'
b. De UUID inimage_id
komt overeen met:i.id = (elem->>'image_id')::uuid
-
Voor afbeeldingstypen, waar een overeenkomende afbeelding is gevonden
c.elem->>'type' = 'image' AND i.id IS NOT NULL
verwijder de sleutel 'image_id' en voeg de gerelateerde afbeeldingsrij toe als
jsonb
waarde:elem - 'image_id' || jsonb_build_object('image', i)
Bewaar anders het originele element.
-
Voeg de gewijzigde elementen opnieuw samen tot een nieuwe
content
kolom metjsonb_agg()
. -
Onvoorwaardelijk
LEFT JOIN LATERAL
het resultaat naarposts
en selecteer alle kolommen, vervang alleenp.content
met de gegenereerde vervangingc.content
-
In de buitenste
SELECT
, converteer de hele rij naarjsonb
met een simpeleto_jsonb()
.
Alle jsonb
functies worden hier in de handleiding beschreven.