Supponendo almeno Postgres 9.5, questo farà il lavoro:
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;
Come?
-
Annulla l'annidamento di
jsonb
array, producendo 1 riga per elemento dell'array:jsonb_array_elements(p.content) AS c(elem)
-
Per ogni elemento
LEFT JOIN
aimages
alle condizioni che
a. La chiave 'tipo' ha il valore 'immagine':c.elem->>'type' = 'image'
b. L'UUID inimage_id
corrisponde a:i.id = (elem->>'image_id')::uuid
-
Per i tipi di immagine, dove è stata trovata un'immagine corrispondente
c.elem->>'type' = 'image' AND i.id IS NOT NULL
rimuovi la chiave 'image_id' e aggiungi la relativa riga dell'immagine come
jsonb
valore:elem - 'image_id' || jsonb_build_object('image', i)
Altrimenti mantieni l'elemento originale.
-
Riaggrega gli elementi modificati in un nuovo
content
colonna conjsonb_agg()
. -
Incondizionatamente
LEFT JOIN LATERAL
il risultato inposts
e seleziona tutte le colonne, sostituisci solop.content
con la sostituzione generatac.content
-
Nel
SELECT
esterno , converti l'intera riga injsonb
con un sempliceto_jsonb()
.
Tutto jsonb
le funzioni sono documentate nel manuale qui.