2017-08-09 2 views
1

Comment est-ce que je peux aplatir récursivement un jsonb imbriqué dans postgres dont je ne connais pas la profondeur et le champ à chaque profondeur? (Voir exemple ci-dessous)aplatit récursivement un jsonb imbriqué dans des postgres sans profondeur inconnue et avec des champs de clé inconnus

Une requête PostgresSQL à faire l'aplanissement serait beaucoup aprécié

{ 
     "xx": "", 
     "xx": "", 
     "form": "xxx", 
     "type": "", 
     "content_type": "xxx", 
     "reported_date": , 
     "contact": { 
      "imported_date": "", 
      "name": "", 
      "phone": "", 
      "alternate_phone": "", 
      "specialization": "", 
      "type": "", 
      "reported_date": , 
      "parent": { 
       "_id": "xxx", 
       "_rev": "xxx", 
       "parent": "", 
       "type": "xxx" 
       } 
     } 
    } 

J'ai cherché dans le débordement de la pile, mais ils considèrent que jsonb ce qui ont une profondeur unique et les clés sont déjà connues avant

Répondre

1

Exemple de configuration:

create table my_table(id int, data jsonb); 
insert into my_table values 
(1, 
$${ 
    "type": "a type", 
    "form": "a form", 
    "contact": { 
     "name": "a name", 
     "phone": "123-456-78", 
     "type": "contact type", 
     "parent": { 
      "id": "444", 
      "type": "parent type" 
      } 
    } 
}$$); 

La requête récursive exécute pour chaque objet jsonb_each() JSON trouvé sur tout le vel. De nouveaux noms clés contiennent le chemin complet de la racine:

with recursive flat (id, key, value) as (
    select id, key, value 
    from my_table, 
    jsonb_each(data) 
union 
    select f.id, concat(f.key, '.', j.key), j.value 
    from flat f, 
    jsonb_each(f.value) j 
    where jsonb_typeof(f.value) = 'object' 
) 
select id, jsonb_pretty(jsonb_object_agg(key, value)) as data 
from flat 
where jsonb_typeof(value) <> 'object' 
group by id; 

id |     data     
----+------------------------------------------ 
    1 | {          + 
    |  "form": "a form",     + 
    |  "type": "a type",     + 
    |  "contact.name": "a name",   + 
    |  "contact.type": "contact type",  + 
    |  "contact.phone": "123-456-78",  + 
    |  "contact.parent.id": "444",   + 
    |  "contact.parent.type": "parent type"+ 
    | } 
(1 row) 

Si vous souhaitez obtenir une vue à plat de ces données, vous pouvez utiliser la fonction create_jsonb_flat_view() décrit dans cette réponse Flatten aggregated key/value pairs from a JSONB field?

Vous devez créer une table (ou vue) avec jsonb aplaties:

create table my_table_flat as 
-- create view my_table_flat as 
with recursive flat (id, key, value) as (
-- etc as above 
-- but without jsonb_pretty() 

maintenant, vous pouvez utiliser la fonction sur la table:

select create_jsonb_flat_view('my_table_flat', 'id', 'data'); 

select * from my_table_flat_view; 


id | contact.name | contact.parent.id | contact.parent.type | contact.phone | contact.type | form | type 
----+--------------+-------------------+---------------------+---------------+--------------+--------+-------- 
    1 | a name  | 444    | parent type   | 123-456-78 | contact type | a form | a type 
(1 row) 

La solution fonctionne dans Postgres 9.5+, car elle utilise la fonction jsonb introduite dans cette version. Si la version de votre serveur est plus ancienne, il est fortement recommandé de mettre à jour Postgres pour utiliser efficacement jsonb.

+0

Merci beaucoup klin !. Comment puis-je créer ceci ci-dessus dans une vue avec chaque élément en tant que colonne? – ros

+0

aussi son dit 'fonction jsonb_object_agg (texte, jsonb) n'existe pas' quelle est la solution de contournement de cela? – ros

+1

Voir la réponse mise à jour. – klin