Unter der Annahme von mindestens Postgres 9.5 wird dies die Aufgabe erledigen:
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;
Wie?
-
Entschachteln Sie
jsonb
Array, das 1 Zeile pro Array-Element erzeugt:jsonb_array_elements(p.content) AS c(elem)
-
Für jedes Element
LEFT JOIN
zuimages
unter den Bedingungen, dass
a. Der Schlüssel 'Typ' hat den Wert 'Bild':c.elem->>'type' = 'image'
b. Die UUID inimage_id
Übereinstimmungen:i.id = (elem->>'image_id')::uuid
-
Für Bildtypen, bei denen ein passendes Bild gefunden wurde
c.elem->>'type' = 'image' AND i.id IS NOT NULL
Entfernen Sie den Schlüssel „image_id“ und fügen Sie die zugehörige Bildzeile als
jsonb
hinzu Wert:elem - 'image_id' || jsonb_build_object('image', i)
Andernfalls behalten Sie das ursprüngliche Element.
-
Reaggregieren Sie die geänderten Elemente zu einem neuen
content
Spalte mitjsonb_agg()
. -
Unbedingt
LEFT JOIN LATERAL
das Ergebnis anposts
und alle Spalten auswählen, nurp.content
ersetzen mit dem generierten Ersatzc.content
-
Im äußeren
SELECT
, konvertieren Sie die gesamte Zeile injsonb
mit einem einfachento_jsonb()
.
Alle jsonb
Funktionen sind im Handbuch hier dokumentiert.