PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment joindre des éléments de tableau jsonb dans Postgres ?

En supposant au moins Postgres 9.5, cela fera l'affaire :

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;

Comment ?

  1. Désimbriquer le jsonb tableau, produisant 1 ligne par élément de tableau :

    jsonb_array_elements(p.content) AS c(elem)
    
  2. Pour chaque élément LEFT JOIN en images aux conditions que
    a. La clé 'type' a la valeur 'image' :c.elem->>'type' = 'image'
    b. L'UUID dans image_id correspond à :i.id = (elem->>'image_id')::uuid

  3. Pour les types d'images, où une image correspondante a été trouvée

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

    supprimez la clé 'image_id' et ajoutez la ligne d'image associée en tant que jsonb valeur :

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

    Sinon, conservez l'élément d'origine.

  4. Réagréger les éléments modifiés dans un nouveau content colonne avec jsonb_agg() .

  5. Inconditionnellement LEFT JOIN LATERAL le résultat aux posts et sélectionnez toutes les colonnes, remplacez uniquement p.content avec le remplacement généré c.content

  6. Dans le SELECT externe , convertissez toute la ligne en jsonb avec un simple to_jsonb() .

Tous jsonb les fonctions sont documentées dans le manuel ici.