web-dev-qa-db-fra.com

Comment rechercher une chaîne spécifique dans une colonne de type de données JSON Postgres?

J'ai une colonne nommée params dans une table nommée reports qui contient JSON.

J'ai besoin de trouver quelles lignes contiennent le texte "authVar" n'importe où dans le tableau JSON. Je ne connais pas le chemin ou le niveau dans lequel le texte pourrait apparaître.

Je veux simplement rechercher dans le JSON avec un opérateur standard.

Quelque chose comme:

SELECT * FROM reports
WHERE params LIKE '%authVar%'

J'ai cherché, recherché sur Google et lu la documentation de Postgres. Je ne comprends pas très bien le type de données JSON et je pense qu'il me manque quelque chose de facile.

Le JSON ressemble à ceci.

[  
   {  
      "tileId":18811,
      "Params":{  
         "data":[  
            {  
               "name":"Week Ending",
               "color":"#27B5E1",
               "report":"report1",
               "locations":{  
                  "c1":0,
                  "c2":0,
                  "r1":"authVar",
                  "r2":66
               }
            }
         ]
      }
   }
]
14
Joshua Dance

Il est possible de parcourir récursivement une structure json inconnue, mais ce serait plutôt complexe et coûteux. Je proposerais la méthode de la force brute qui devrait bien fonctionner:

select *
from reports
where params::text like '%authVar%';
-- or 
-- where params::text like '%"authVar"%';
-- if you are looking for the exact value

La requête est très rapide mais peut renvoyer des lignes supplémentaires inattendues dans les cas où la chaîne recherchée fait partie d'une des clés.

Dans Postgres 12 la recherche récursive dans JSONB est assez confortable avec la nouvelle fonctionnalité de jsonpath.

Trouvez une valeur de chaîne contenant authVar:

select *
from reports
where jsonb_path_exists(params, '$.** ? (@.type() == "string" && @ like_regex "authVar")')

Le jsonpath:

$.**                     find any value at any level (recursive processing)
?                        where
@.type() == "string"     value is string
&&                       and
@ like_regex "authVar"   value contains 'authVar'

Ou trouvez la valeur exacte:

select *
from reports
where jsonb_path_exists(params, '$.** ? (@ == "authVar")')

A lire dans la documentation:

25
klin