Деструктуризация глубоко вложенных json в запросе - PullRequest
1 голос
/ 09 июля 2020

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

create temporary table testing (id integer, contents json);

insert into testing values (1, '{
    "level1": {
        "level2": [
            {
                "level3": {
                    "a": {
                        "value1": 1,
                        "value2": 2
                    },
                    "b": {
                        "value1": 3,
                        "value2": 4
                    }
                }
            },
            {
                "level3": {
                    "d": {
                        "value1": 5,
                        "value2": 6
                    },
                    "e": {
                        "value1": 7,
                        "value2": 8
                    }
                }
            }
        ]
    }
}
');

Я пытаюсь получить следующий результат:

| id | l2_label | data_label | value1 |
+----+----------+------------+--------+
| 1  | level2   | a          | 1      |
| 1  | level2   | b          | 3      |
| 1  | level2   | d          | 5      |
| 1  | level2   | e          | 7      |

Верхний уровень всегда называется «level1», но их может быть больше внутри там один ключ и "level2" не является фиксированной строкой. Каждый из этих ключей содержит массив объектов, которые могут иметь больше, чем ключ «level3», но я ищу только «level3». Внутри «a», «b», «c» может быть любая строка. Затем я ищу по одной строке для каждого значения "value1".

Я получил следующий запрос:

select id, key as l2_label, json_array_elements(value) from testing, json_each(contents -> 'level1');

, который возвращает

 id | l2_label |         json_array_elements
----+----------+--------------------------------------
  1 | level2   | {                                   +
    |          |                 "level3": {         +
    |          |                     "a": {          +
    |          |                         "value1": 1,+
    |          |                         "value2": 2 +
    |          |                     },              +
    |          |                     "b": {          +
    |          |                         "value1": 3,+
    |          |                         "value2": 4 +
    |          |                     }               +
    |          |                 }                   +
    |          |             }
  1 | level2   | {                                   +
    |          |                 "level3": {         +

но я не понимаю, как теперь распаковать элементы level3.

Мой вопрос, во-первых, как получить результат, который я ищу, а также советы о том, как построить такой запрос постепенно , так как я не знаю, как действовать с этим json_array_elements сейчас.

Ответы [ 2 ]

1 голос
/ 09 июля 2020

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

with testing as (
  select 1 as id, '{
    "level1": {
        "level2": [
            {
                "level3": {
                    "a": {
                        "value1": 1,
                        "value2": 2
                    },
                    "b": {
                        "value1": 3,
                        "value2": 4
                    }
                }
            },
            {
                "level3": {
                    "d": {
                        "value1": 5,
                        "value2": 6
                    },
                    "e": {
                        "value1": 7,
                        "value2": 8
                    }
                }
            }
        ]
    }
}
'::json as contents
), keys_lvl_2 as (
  select id,
         json_object_keys(contents->'level1') as l2_label,
         contents->'level1' as contents
    from testing
), array_lvl_2 as (
  select id, l2_label,
         json_array_elements(contents->l2_label) as contents
    from keys_lvl_2
), keys_lvl_3 as (
  select id, l2_label,
         json_object_keys(contents->'level3') as data_label,
         contents->'level3' as contents
    from array_lvl_2
)
-- select * from keys_lvl_2;
-- select * from array_lvl_2;
-- select * from keys_lvl_3;
select id, l2_label, data_label,
       contents->data_label->>'value1' as value1
  from keys_lvl_3;

1 голос
/ 09 июля 2020

Один из способов достижения этого - использование бокового соединения, при котором мы вычисляем заданное значение для невложенного набора ключей.

Например:

WITH getting_lvl3 AS (
  SELECT id                                     AS id,
         key                                    AS l2_label,
         json_array_elements(value) -> 'level3' AS lvl3
  FROM testing, json_each(contents -> 'level1')
)
SELECT id,
       l2_label,
       label,
       lvl3 -> label -> 'value1' -- Getting value1 for each key
FROM getting_lvl3
       -- Executing this code for every key in level 3
       LEFT JOIN LATERAL json_object_keys(lvl3) label ON TRUE
;

результат должен выглядеть примерно так:

|id |l2_label|label|value|
|---|--------|-----|-----|
|1  |level2  |a    |1    |
|1  |level2  |b    |3    |
|1  |level2  |c    |5    |
|1  |level2  |d    |7    |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...