Как найти определенную строку в столбце типа данных JSON Postgres?

У меня есть столбец с именем params в таблице с именем reports, который содержит JSON.

Мне нужно найти, какие строки содержат текст 'authVar' в любом месте массива JSON. Я не знаю путь или уровень, на котором мог бы появиться текст.

Я хочу просто искать через JSON со стандартным оператором like.

Что-то вроде:

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

Я искал, гуглил и читал документы Postgres. Я не очень хорошо понимаю тип данных JSON и считаю, что мне чего-то не хватает.

JSON выглядит примерно так.

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

Ответ 1

Можно рекурсивно пройти через неизвестную структуру JSON, но это будет довольно сложно и дорого. Я бы предложил метод грубой силы, который должен хорошо работать:

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

Запрос очень быстрый, но может возвращать неожиданные дополнительные строки в тех случаях, когда искомая строка является частью одного из ключей.

В Postgres 12 рекурсивный поиск в JSONB довольно удобен с новой функцией jsonpath.

Найдите строковое значение, содержащее authVar:

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

Jsonpath:

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

Или найдите точное значение:

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

Прочтите в документации: