Che*_*yne 6 postgresql recursion json
我在JSON数据类型(Postgres 9.3)下存储了Postgres中的JSON文档,我需要以递归方式从树中收集密钥名称.
例如,给定这个JSON树
{
"files": {
"folder": {
"file1": {
"property": "blah"
},
"file2": {
"property": "blah"
},
"file3": {
"property": "blah"
},
"file4": {
"property": "blah"
}
}
},
"software": {
"apt": {
"package1": {
"version": 1.2
},
"package2": {
"version": 1.2
},
"package3": {
"version": 1.2
},
"package4": {
"version": 1.2
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想提取类似[file1,file2,file3,file3,package1,package2,package3,package4]的东西
基本上只是我可以用于文本搜索索引的键列表.
我知道我可以使用类似的东西获得最外层对象的键列表
SELECT DISTINCT(json_object_keys(data))
Run Code Online (Sandbox Code Playgroud)
而且我知道可以用类似的东西递归地爬过树
WITH RECURSIVE data()
Run Code Online (Sandbox Code Playgroud)
但我把两者放在一起很麻烦.
有人可以帮忙吗?
诀窍是json_typeof在正确的位置添加一些最终条件测试.
jsonb如果您不关心对象键顺序,您也应该使用.
这是我的工作环境:
CREATE TABLE test (
id SERIAL PRIMARY KEY,
doc JSON
);
INSERT INTO test (doc) VALUES ('{
"files": {
"folder": {
"file1": {
"property": "blah"
},
"file2": {
"property": "blah"
},
"file3": {
"property": "blah"
},
"file4": {
"property": "blah",
"prop" : {
"clap": "clap"
}
}
}
},
"software": {
"apt": {
"package1": {
"version": 1.2
},
"package2": {
"version": 1.2
},
"package3": {
"version": 1.2
},
"package4": {
"version": 1.2
}
}
}
}');
Run Code Online (Sandbox Code Playgroud)
当第二个查询未返回任何行时,将停止递归.这是通过传递一个空对象来完成的json_each.
WITH RECURSIVE doc_key_and_value_recursive(key, value) AS (
SELECT
t.key,
t.value
FROM test, json_each(test.doc) AS t
UNION ALL
SELECT
t.key,
t.value
FROM doc_key_and_value_recursive,
json_each(CASE
WHEN json_typeof(doc_key_and_value_recursive.value) <> 'object' THEN '{}' :: JSON
ELSE doc_key_and_value_recursive.value
END) AS t
)
SELECT *
FROM doc_key_and_value_recursive
WHERE json_typeof(doc_key_and_value_recursive.value) <> 'object';
Run Code Online (Sandbox Code Playgroud)
我写了一个函数来做到这一点:
CREATE OR REPLACE FUNCTION public.jsonb_keys_recursive(_value jsonb)
RETURNS TABLE(key text)
LANGUAGE sql
AS $function$
WITH RECURSIVE _tree (key, value) AS (
SELECT
NULL AS key,
_value AS value
UNION ALL
(WITH typed_values AS (SELECT jsonb_typeof(value) as typeof, value FROM _tree)
SELECT v.*
FROM typed_values, LATERAL jsonb_each(value) v
WHERE typeof = 'object'
UNION ALL
SELECT NULL, element
FROM typed_values, LATERAL jsonb_array_elements(value) element
WHERE typeof = 'array'
)
)
SELECT DISTINCT key
FROM _tree
WHERE key IS NOT NULL
$function$;
Run Code Online (Sandbox Code Playgroud)
例如,尝试:
SELECT jsonb_keys_recursive('{"A":[[[{"C":"B"}]]],"X":"Y"}');
Run Code Online (Sandbox Code Playgroud)
请注意,其他两个答案在数组内的对象中找不到键,我的解决方案确实如此.(问题根本没有给出任何数组的例子,所以在数组中查找键可能不是原始提问者所需要的,但这正是我所需要的.)
| 归档时间: |
|
| 查看次数: |
3921 次 |
| 最近记录: |