2017-10-12 3 views
0

Je suis très nouveau dans le domaine PG jsonb. J'ai par exemple un champ jsonb contenant les éléments suivantsPostgresql jsonb traversal

{ 
"RootModule": { 
    "path": [ 
    1 
    ], 
    "tags": { 
    "ModuleBase1": { 
     "value": 40640, 
     "humanstring": "40640" 
    }, 
    "ModuleBase2": { 
    "value": 40200, 
    "humanstring": "40200" 
    } 
    }, 
"children": { 
    "RtuInfoModule": { 
    "path": [ 
     1, 
     0 
    ], 
    "tags": { 
     "in0": { 
     "value": 11172, 
     "humanstring": "11172" 
     }, 
     "in1": { 
     "value": 25913, 
     "humanstring": "25913" 
     } 
etc.... 

Est-il possible d'interroger les niveaux X de profondeur et rechercher la clé d'une certaine clé « tags ». Dire que je veux "ModuleBase2" et "in1" et je veux obtenir leurs valeurs?

Fondamentalement, je cherche une requête qui traversera un champ jsonb jusqu'à ce qu'il trouve une clé et renvoie la valeur sans avoir à connaître la structure.

En Python ou JS, une simple fonction de boucle ou récursive peut facilement traverser un objet json (ou un dictionnaire) jusqu'à ce qu'il trouve une clé.

Y at-il une fonction intégrée PG doit faire cela?

Finalement, je veux le faire dans django.

Edit: Je vois que je peux faire des choses comme

SELECT data.key AS key, data.value as value 
FROM trending_snapshot, jsonb_each(trending_snapshot.snapshot- 
>'RootModule') AS data 
WHERE key = 'tags'; 

Mais je dois préciser les niveaux.

Répondre

0

Vous pouvez utiliser une requête récursive pour aplatir un jsonb imbriquée, voir this answer. Modifier la requête pour trouver des valeurs pour les clés spécifiques (ajouter une condition à where clause):

with recursive flat (id, path, value) as (
    select id, key, value 
    from my_table, 
    jsonb_each(data) 
union 
    select f.id, concat(f.path, '.', j.key), j.value 
    from flat f, 
    jsonb_each(f.value) j 
    where jsonb_typeof(f.value) = 'object' 
) 
select id, path, value 
from flat 
where path like any(array['%ModuleBase2.value', '%in1.value']); 

id |      path      | value 
----+--------------------------------------------------+------- 
    1 | RootModule.tags.ModuleBase2.value    | 40200 
    1 | RootModule.children.RtuInfoModule.tags.in1.value | 25913 
(2 rows)  

test dans SqlFiddle.

+0

Oh wow. C'est vraiment cool. Merci beaucoup. L'idée de SQL récursif est maintenant aussi nouvelle pour moi. Fonctionne très bien. Et j'imagine que l'édition de la clause where peut facilement produire différents résultats souhaités. –

+0

Oui, vous pouvez contrôler les résultats en modifiant la condition. – klin

+0

Vous êtes un sauveteur –