Sql 关于嵌套/递归元素的Postgres JSONB查询
我有一个嵌套的层次结构,用JSON表达,例如:Sql 关于嵌套/递归元素的Postgres JSONB查询,sql,json,postgresql,Sql,Json,Postgresql,我有一个嵌套的层次结构,用JSON表达,例如: { "id":1, "children": [ { "id":2 }, { "id": 3, "children": [ { "id": 4 } ] } ] } postgres能否回答一个查询:记录是否在文档的任何部分包含“id”:4 如果是,这些查询是否由9.4版中添加的JSONB索引支持?更新:感谢reddit上的Theralgaxbo,我们从我的原始
{
"id":1,
"children": [
{ "id":2 },
{ "id": 3, "children": [
{ "id": 4 }
]
}
]
}
postgres能否回答一个查询:记录是否在文档的任何部分包含“id”:4
如果是,这些查询是否由9.4版中添加的JSONB索引支持?更新:感谢reddit上的Theralgaxbo,我们从我的原始代码开始,开发了更简洁的代码:
with recursive deconstruct (jsonlevel) as(
values ('{"id":1,"children":[{"id":2},{"id":3,"children":[{"id":4}]}]}'::json)
union all
select
case left(jsonlevel::text, 1)
when '{' then (json_each(jsonlevel)).value
when '[' then json_array_elements(jsonlevel)
end as jsonlevel
from
deconstruct
where
left(jsonlevel::text, 1) in ('{', '[')
)
select * from deconstruct where case when left(jsonlevel::text, 1) = '{' then jsonlevel->>'id' = '4' else false end;
我的原始答复如下:
我疯狂地进行实验,最终得出了如下结论:
with recursive ret(jsondata) as
(select row_to_json(col)::text jsondata from
json_each('{
"id":1,
"children": [
{ "id":2 },
{ "id": 3, "children": [
{ "id": 4 }
]
}
]
}'::json) col
union
select case when left(jsondata::text,1)='[' then row_to_json(json_each(json_array_elements(jsondata)))::text
when left((jsondata->>'value'),2)='{}' then null::text
when left((jsondata->>'value')::text,1)='[' then row_to_json(json_each(json_array_elements(jsondata->'value')))::text
else ('{"key":'||(jsondata->'key')||', "value":'||(jsondata->'value')||'}')::json::text end jsondata
from (
select row_to_json(json_each(ret.jsondata::json)) jsondata
from ret) xyz
)
select max(1) from ret
where jsondata::json->>'key'='id'
and jsondata::json->>'value'='1'
遗憾的是,我尝试用9.3解决这个问题,但是在让相同的代码在对象和数组上运行时遇到了问题。事实上,我认为在9.4中这可能要容易得多。我开始编写一个递归查询来完成它,但唉,我失败了——反正今天就失败了。不管怎样,我想出了一个方法,根据json字段文本表示的第一个字符来检测它是数组还是对象。可能无法直接回答您的问题,但我使用JSONSelect和PLV8来处理更复杂的JSON遍历和查询任务。花了一些时间进行设置,但它对我们来说运行良好。请随意编辑此内容,我实际上希望看到改进完成,或者当您向它抛出大量不同的数据时,您至少可以指出任何错误。感谢Joe提供的代码。老实说,您的SQL刚刚证实了我的担忧——它太复杂了,我无法证明它的合理性——我不希望团队中的每个人都成为博士后大师,以便了解发生了什么。我想我有两个选择:将我的JSON层次结构扁平化为一个带有ParentID的简单列表,或者忘记在Postgres中执行此操作,并在应用程序级别进行查询。有了9.4和jsonb,这将更容易。。现在,如果需要的话,您可以很容易地编写一个函数来隐藏一些复杂性。此外,如果您愿意安装V8语言,它具有javascript的功能,javascript甚至更支持JSON。