En supposant au moins Postgres 9.5, cela fera l'affaire :
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;
Comment ?
-
Désimbriquer le
jsonb
tableau, produisant 1 ligne par élément de tableau :jsonb_array_elements(p.content) AS c(elem)
-
Pour chaque élément
LEFT JOIN
enimages
aux conditions que
a. La clé 'type' a la valeur 'image' :c.elem->>'type' = 'image'
b. L'UUID dansimage_id
correspond à :i.id = (elem->>'image_id')::uuid
-
Pour les types d'images, où une image correspondante a été trouvée
c.elem->>'type' = 'image' AND i.id IS NOT NULL
supprimez la clé 'image_id' et ajoutez la ligne d'image associée en tant que
jsonb
valeur :elem - 'image_id' || jsonb_build_object('image', i)
Sinon, conservez l'élément d'origine.
-
Réagréger les éléments modifiés dans un nouveau
content
colonne avecjsonb_agg()
. -
Inconditionnellement
LEFT JOIN LATERAL
le résultat auxposts
et sélectionnez toutes les colonnes, remplacez uniquementp.content
avec le remplacement généréc.content
-
Dans le
SELECT
externe , convertissez toute la ligne enjsonb
avec un simpleto_jsonb()
.
Tous jsonb
les fonctions sont documentées dans le manuel ici.