Postgresql 递归JSONB postgres

Postgresql 递归JSONB postgres,postgresql,jsonb,recursive-cte,Postgresql,Jsonb,Recursive Cte,我试图在Postgres中构建一个同时支持数组和对象的递归CTE,以返回键值对列表,但似乎找不到一个好的示例。这是我当前的代码 with recursive jsonRecurse as ( select j.key as Path ,j.key ,j.value from jsonb_each(to_jsonb('{ "key1": { "key2": [ { "key3": "test3",

我试图在Postgres中构建一个同时支持数组和对象的递归CTE,以返回键值对列表,但似乎找不到一个好的示例。这是我当前的代码

with recursive jsonRecurse as
(
select
j.key as Path
,j.key
,j.value
from jsonb_each(to_jsonb('{
    "key1": {
        "key2": [
            {
                "key3": "test3",
                "key4": "test4"
            }
        ]
    },
    "key5": [
        {
            "key6":
            [
                {
                    "key7": "test7"
                }
            ]
        }
    ]
}'::jsonb)) j

union all

select
jr.path || '.' || jr2.Key
,jr2.key
,jr2.value
from jsonRecurse jr
       left join lateral jsonb_each(jr.value) jr2 on true
where jsonb_typeof(jr.value) = 'object'
)

select
*
from jsonRecurse;

正如您所看到的,只要我点击一个数组而不是一个对象,代码就会停止递归。我尝试过使用case语句,并将对jsonb_each或jsonb_array_元素的函数调用放在case语句中,但我收到一个错误,告诉我应该使用横向联接。

我使用此示例表使查询更具可读性:

create table my_table(id serial primary key, jdata jsonb);
insert into my_table (jdata) values
('{
    "key1": {
        "key2": [
            {
                "key3": "test3",
                "key4": "test4"
            }
        ]
    },
    "key5": [
        {
            "key6":
            [
                {
                    "key7": "test7"
                }
            ]
        }
    ]
}');
根据
value
的类型,必须有条件地连接
jsonb\u每个(值)
jsonb\u数组元素(值)

with recursive extract_all as
(
    select 
        key as path, 
        value
    from my_table
    cross join lateral jsonb_each(jdata)
union all
    select
        path || '.' || coalesce(obj_key, (arr_key- 1)::text),
        coalesce(obj_value, arr_value)
    from extract_all
    left join lateral 
        jsonb_each(case jsonb_typeof(value) when 'object' then value end) 
        as o(obj_key, obj_value) 
        on jsonb_typeof(value) = 'object'
    left join lateral 
        jsonb_array_elements(case jsonb_typeof(value) when 'array' then value end) 
        with ordinality as a(arr_value, arr_key)
        on jsonb_typeof(value) = 'array'
    where obj_key is not null or arr_key is not null
)
select *
from extract_all;
输出:

        path        |                     value                      
--------------------+------------------------------------------------
 key1               | {"key2": [{"key3": "test3", "key4": "test4"}]}
 key5               | [{"key6": [{"key7": "test7"}]}]
 key1.key2          | [{"key3": "test3", "key4": "test4"}]
 key5.0             | {"key6": [{"key7": "test7"}]}
 key1.key2.0        | {"key3": "test3", "key4": "test4"}
 key5.0.key6        | [{"key7": "test7"}]
 key1.key2.0.key3   | "test3"
 key1.key2.0.key4   | "test4"
 key5.0.key6.0      | {"key7": "test7"}
 key5.0.key6.0.key7 | "test7"
(10 rows)
json数组的元素没有键,我们应该使用它们的索引来构建路径。因此,函数
jsonb_array_elements()
应按顺序调用。Per(见7.2.1.4.表格功能):

如果指定了WITH ORDINALITY子句,将向函数结果列中添加一个bigint类型的附加列。此列对函数结果集的行进行编号,从1开始

函数调用

jsonb_array_elements(case jsonb_typeof(value) when 'array' then value end) 
with ordinality as a(arr_value, arr_key)

返回成对的
(值,序数)
别名为
(arr\u值,arr\u键)

啊哈,我以为条件联接是前进的方向,但我不知道如何使它工作。
横向联接中的函数调用中的
case
语句似乎就是我所缺少的魔力。我可以问一下带序数的
语句在做什么吗?