sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo unir elementos de matriz jsonb en Postgres?

Asumiendo al menos Postgres 9.5, esto hará el trabajo:

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;

¿Cómo?

  1. Desanime el jsonb matriz, produciendo 1 fila por elemento de matriz:

    jsonb_array_elements(p.content) AS c(elem)
    
  2. Para cada elemento LEFT JOIN a images en las condiciones que
    a. La clave 'tipo' tiene el valor 'imagen':c.elem->>'type' = 'image'
    b. El UUID en image_id coincidencias:i.id = (elem->>'image_id')::uuid

  3. Para tipos de imágenes, donde se encontró una imagen coincidente

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

    elimine la clave 'image_id' y agregue la fila de imagen relacionada como jsonb valor:

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

    De lo contrario, conserve el elemento original.

  4. Vuelva a agregar los elementos modificados a un nuevo content columna con jsonb_agg() .

  5. Incondicionalmente LEFT JOIN LATERAL el resultado a posts y seleccione todas las columnas, solo reemplace p.content con el reemplazo generado c.content

  6. En el exterior SELECT , convierte toda la fila a jsonb con un simple to_jsonb() .

Todos jsonb Las funciones están documentadas en el manual aquí.