Zakładając co najmniej Postgres 9.5, wykona to zadanie:
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;
Jak?
-
Odblokuj
jsonb
tablica, tworząc 1 wiersz na element tablicy:jsonb_array_elements(p.content) AS c(elem)
-
Dla każdego elementu
LEFT JOIN
doimages
na warunkach, które
a. Klucz „typ” ma wartość „obraz”:c.elem->>'type' = 'image'
b. Identyfikator UUID wimage_id
dopasowania:i.id = (elem->>'image_id')::uuid
-
W przypadku typów obrazów, w których znaleziono pasujący obraz
c.elem->>'type' = 'image' AND i.id IS NOT NULL
usuń klucz „image_id” i dodaj powiązany wiersz obrazu jako
jsonb
wartość:elem - 'image_id' || jsonb_build_object('image', i)
W przeciwnym razie zachowaj oryginalny element.
-
Ponowna agregacja zmodyfikowanych elementów do nowej
content
kolumna zjsonb_agg()
. -
Bezwarunkowo
LEFT JOIN LATERAL
wynik doposts
i zaznacz wszystkie kolumny, zamień tylkop.content
z wygenerowanym zamiennikiemc.content
-
W zewnętrznym
SELECT
, przekonwertuj cały wiersz najsonb
za pomocą prostegoto_jsonb()
.
Wszystkie jsonb
funkcje są opisane w instrukcji tutaj.