Запрос столбца JSONB для любого значения где =? - PullRequest
2 голосов
/ 21 сентября 2019

У меня есть столбец jsonb, который, к сожалению, очень непредсказуем, в некоторых случаях его значением может быть массив с вложенными значениями:

["UserMailer", "applicant_setup_3", ["5cbffeb7-8d5e-4b52-a475-3cf320b2cee9"]]

Иногда это будет что-то с ключом / значениями, напримерthis:

[{"reference_id": "5cbffeb7-8d5e-4b52-a475-3cf320b2cee9", "job_dictionary": ["StatusUpdater", "FollowTwitterUsersJob"]}]

Есть ли способ написать запрос, который просто обрабатывает весь столбец как текст и делает like, чтобы посмотреть, смогу ли я найти uuid в большом текстовом объекте?Я хочу найти все записи, в которых есть определенная строка uuid в столбце jsonb.

Запрос не должен быть быстрым или эффективным.

Ответы [ 3 ]

2 голосов
/ 21 сентября 2019

В Postgres есть оператор поиска ? для jsonb, но для этого потребуется рекурсивный поиск в содержимом json.

Возможный, хотя и не очень эффективный метод, позволил бы структурировать объект и использовать LIKEдля поиска:

myjsonb::text LIKE '%"5cbffeb7-8d5e-4b52-a475-3cf320b2cee9"%'
myjsonb::text LIKE '%"' || myuuid || '"%'

Демонстрация на DB Fiddle :

1 голос
/ 22 сентября 2019

Проблема с оператором jsonb ? заключается в том, что он рассматривает только ключи верхнего уровня * (включая элементы массива), а не значений и никаких вложенных объектов.

Вы, похоже, ищете значений и элементов массива (не ключи) на любом уровне.Это можно получить с помощью полнотекстового поиска в верхней части столбца json (b):

SELECT * FROM tbl
WHERE  to_tsvector('simple', jsonb_column)
    @@ tsquery '5cbffeb7-8d5e-4b52-a475-3cf320b2cee9';

db <> fiddle здесь

to_tsvector() извлекает значения и элементы массива на все уровни - именно то, что вам нужно.

Требуется Postgres 10 илипотом.json(b)_to_tsvector() в Postgres 11 предлагает больше гибкости.

Это привлекательно для таблиц нетривиального размера, так как его можно поддерживать с полным текстом index очень эффективно:

CREATE INDEX tbl_jsonb_column_fts_gin_idx ON tbl USING GIN (to_tsvector('simple', jsonb_column));

Я использую текст 'simple'поиск конфигурации в примере.Возможно, вы захотите выбрать язык, например 'english'.Не имеет большого значения, пока вы ищите только строки UUID, но использование для определенного языка может сделать индекс немного меньше ...

Related:

Пока выищите только UUID, вы можете оптимизировать его с помощью пользовательской (IMMUTABLE) функции для извлечения UUID из документа JSON в виде массива (uuid[]) и построения функционального индекса GIN поверх него.(Значительно меньший индекс, но.) Тогда:

SELECT * FROM tbl
WHERE  my_uuid_extractor(jsonb_column) @> '{5cbffeb7-8d5e-4b52-a475-3cf320b2cee9}';

Такая функция может быть дорогой, но не имеет большого значения с функциональным индексом, который хранит и работает с предварительно вычисленными значениями.

1 голос
/ 21 сентября 2019

Вы можете сначала разделить элементы массива с помощью jsonb_array_elements(json), а затем отфильтровать приведенную строку из этих элементов с помощью оператора

select q.elm
  from
  (
    select jsonb_array_elements(js) as elm
      from tab
  ) q
 where elm::varchar like '%User%'

elm
----------------------------------------------------------------------------------------------------------------------
"UserMailer"
{"reference_id": "5cbffeb7-8d5e-4b52-a475-3cf320b2cee9", "job_dictionary": ["StatusUpdater", "FollowTwitterUsersJob"]}

Демо

...