PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come unire gli elementi dell'array jsonb in Postgres?

Supponendo almeno Postgres 9.5, questo farà il lavoro:

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;

Come?

  1. Annulla l'annidamento di jsonb array, producendo 1 riga per elemento dell'array:

    jsonb_array_elements(p.content) AS c(elem)
    
  2. Per ogni elemento LEFT JOIN a images alle condizioni che
    a. La chiave 'tipo' ha il valore 'immagine':c.elem->>'type' = 'image'
    b. L'UUID in image_id corrisponde a:i.id = (elem->>'image_id')::uuid

  3. Per i tipi di immagine, dove è stata trovata un'immagine corrispondente

    c.elem->>'type' = 'image' AND i.id IS NOT NULL
    

    rimuovi la chiave 'image_id' e aggiungi la relativa riga dell'immagine come jsonb valore:

    elem - 'image_id' || jsonb_build_object('image', i)
    

    Altrimenti mantieni l'elemento originale.

  4. Riaggrega gli elementi modificati in un nuovo content colonna con jsonb_agg() .

  5. Incondizionatamente LEFT JOIN LATERAL il risultato in posts e seleziona tutte le colonne, sostituisci solo p.content con la sostituzione generata c.content

  6. Nel SELECT esterno , converti l'intera riga in jsonb con un semplice to_jsonb() .

Tutto jsonb le funzioni sono documentate nel manuale qui.