Разбор объекта Jsonb в PostgreSql - PullRequest
0 голосов
/ 15 мая 2019

Как разобрать объект jsonb в PostgreSql. Проблема в том, что объект каждый раз отличается структурой внутри. Прямо как ниже.

{  
   "1":{  
      "1":{  
         "level":2,
         "nodeType":2,
         "id":2,
         "parentNode":1,
         "attribute_id":363698007,
         "attribute_text":"Finding site",
         "concept_id":386108004,
         "description_text":"Heart tissue",
         "hierarchy_id":0,
         "description_id":-1,
         "deeperCnt":0,
         "default":false
      },
      "level":1,
      "nodeType":1,
      "id":1,
      "parentNode":0,
      "concept_id":22253000,
      "description_id":37361011,
      "description_text":"Pain",
      "hierarchy_id":404684003,
      "deeperCnt":1,
      "default":false
   },
   "2":{  
      "1":{  
         "attribute_id":"363698007",
         "attribute_text":"Finding site (attribute)",
         "value_id":"321667001",
         "value_text":"Respiratory tract structure (body structure)",
         "default":true
      },
      "level":1,
      "nodeType":1,
      "id":3,
      "parentNode":0,
      "concept_id":11833005,
      "description_id":20419011,
      "description_text":"Dry cough",
      "hierarchy_id":404684003,
      "deeperCnt":1,
      "default":false
   },
   "level":0,
   "recAddedLevel":1,
   "recAddedId":3,
   "nodeType":0,
   "multiple":false,
   "currNodeId":3,
   "id":0,
   "lookForAttributes":false,
   "deeperCnt":2,

}

Так как мне проанализировать весь объект и, например, посмотреть, если внутри объекта есть "attribute_id" = 363698007? В этом случае мы должны получить значение «true» при выборе строк данных в PostgreSql с помощью оператора WHERE.

2 вопрос - какой индекс я должен использовать для столбца jsonb, чтобы получить желаемые результаты? Уже пытались создать индексы btree и gin, но даже простой select возвращает 'null' с помощью sql следующим образом:

SELECT object::jsonb -> 'id' AS id
    FROM table;

если я использую это:

SELECT object
    FROM table;

возвращает впервые описанный объект.

1 Ответ

0 голосов
/ 15 мая 2019

Быстрый и грязный способ (расширен на Сбор рекурсивных ключей JSON в Postgres ):

WITH RECURSIVE doc_key_and_value_recursive(id, key, value) AS (
  SELECT
    my_json.id,
    t.key,
    t.value
  FROM my_json, jsonb_each(my_json.data) AS t

  UNION ALL

  SELECT
    doc_key_and_value_recursive.id,
    t.key,
    t.value
  FROM doc_key_and_value_recursive,
    jsonb_each(CASE 
      WHEN jsonb_typeof(doc_key_and_value_recursive.value) <> 'object' THEN '{}'::jsonb
      ELSE doc_key_and_value_recursive.value
    END) AS t
)
SELECT t.id, t.data->'id' AS id
FROM doc_key_and_value_recursive AS c
INNER JOIN my_json AS t ON (t.id = c.id)
WHERE
    jsonb_typeof(c.value) <> 'object'
    AND c.key = 'attribute_id'
    AND c.value = '363698007'::jsonb;

Онлайн пример: https://dbfiddle.uk/?rdbms=postgres_11&fiddle=57b7c4e817b2dd6580bbf28cbac10981

Это можно значительно улучшить, остановив рекурсию, как только будут найдены соответствующий ключ и значение, обратная сортировка и ограничение 1, также. Но это делает основную вещь в общем.

Это также показывает, что jsonb->'id' работает как положено.

...