少なくともPostgres9.5を想定すると、これでうまくいきます:
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;
どのように?
-
jsonb
のネストを解除します 配列、配列要素ごとに1行を生成します:jsonb_array_elements(p.content) AS c(elem)
-
各要素について
LEFT JOIN
images
へ
a。 キー 'type'には値があります 'image':c.elem->>'type' = 'image'
b。image_id
のUUID 一致:i.id = (elem->>'image_id')::uuid
-
一致する画像が見つかった画像タイプの場合
c.elem->>'type' = 'image' AND i.id IS NOT NULL
キー「image_id」を削除し、関連する画像行を
jsonb
として追加します 値:elem - 'image_id' || jsonb_build_object('image', i)
それ以外の場合は、元の要素を保持します。
-
変更された要素を新しい
content
に再集約しますjsonb_agg()
の列 。 -
無条件に
LEFT JOIN LATERAL
結果をposts
すべての列を選択し、p.content
のみを置き換えます 生成された置換c.content
-
外側の
SELECT
、行全体をjsonb
に変換します 単純なto_jsonb()
を使用します 。
すべてのjsonb
機能については、こちらのマニュアルに記載されています。