PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie verbinde ich jsonb-Array-Elemente in Postgres?

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?

  1. Entschachteln Sie jsonb Array, das 1 Zeile pro Array-Element erzeugt:

    jsonb_array_elements(p.content) AS c(elem)
    
  2. Für jedes Element LEFT JOIN zu images unter den Bedingungen, dass
    a. Der Schlüssel 'Typ' hat den Wert 'Bild':c.elem->>'type' = 'image'
    b. Die UUID in image_id Übereinstimmungen:i.id = (elem->>'image_id')::uuid

  3. 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.

  4. Reaggregieren Sie die geänderten Elemente zu einem neuen content Spalte mit jsonb_agg() .

  5. Unbedingt LEFT JOIN LATERAL das Ergebnis an posts und alle Spalten auswählen, nur p.content ersetzen mit dem generierten Ersatz c.content

  6. Im äußeren SELECT , konvertieren Sie die gesamte Zeile in jsonb mit einem einfachen to_jsonb() .

Alle jsonb Funktionen sind im Handbuch hier dokumentiert.