Asumiendo al menos Postgres 9.5, esto hará el trabajo:
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;
¿Cómo?
-
Desanime el
jsonbmatriz, produciendo 1 fila por elemento de matriz:jsonb_array_elements(p.content) AS c(elem) -
Para cada elemento
LEFT JOINaimagesen las condiciones que
a. La clave 'tipo' tiene el valor 'imagen':c.elem->>'type' = 'image'
b. El UUID enimage_idcoincidencias:i.id = (elem->>'image_id')::uuid -
Para tipos de imágenes, donde se encontró una imagen coincidente
c.elem->>'type' = 'image' AND i.id IS NOT NULLelimine la clave 'image_id' y agregue la fila de imagen relacionada como
jsonbvalor:elem - 'image_id' || jsonb_build_object('image', i)De lo contrario, conserve el elemento original.
-
Vuelva a agregar los elementos modificados a un nuevo
contentcolumna conjsonb_agg(). -
Incondicionalmente
LEFT JOIN LATERALel resultado apostsy seleccione todas las columnas, solo reemplacep.contentcon el reemplazo generadoc.content -
En el exterior
SELECT, convierte toda la fila ajsonbcon un simpleto_jsonb().
Todos jsonb Las funciones están documentadas en el manual aquí.