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
jsonb
matriz, produciendo 1 fila por elemento de matriz:jsonb_array_elements(p.content) AS c(elem)
-
Para cada elemento
LEFT JOIN
aimages
en las condiciones que
a. La clave 'tipo' tiene el valor 'imagen':c.elem->>'type' = 'image'
b. El UUID enimage_id
coincidencias: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 NULL
elimine la clave 'image_id' y agregue la fila de imagen relacionada como
jsonb
valor:elem - 'image_id' || jsonb_build_object('image', i)
De lo contrario, conserve el elemento original.
-
Vuelva a agregar los elementos modificados a un nuevo
content
columna conjsonb_agg()
. -
Incondicionalmente
LEFT JOIN LATERAL
el resultado aposts
y seleccione todas las columnas, solo reemplacep.content
con el reemplazo generadoc.content
-
En el exterior
SELECT
, convierte toda la fila ajsonb
con un simpleto_jsonb()
.
Todos jsonb
Las funciones están documentadas en el manual aquí.