Kob*_*bus 5 postgresql index array json json-path
我正在尝试查询对象数组中存在的键。这种结构:
column jdata
{"name": "Somedata",
"array": [ {"name":"bla1", "attr": "somevalue"},
{"name":"bla2", "otherdata": "somevalue2"},
{"name":"bla3", "otherdata": "somevalue"}
],
"otherstuff": "stuff"
}
Run Code Online (Sandbox Code Playgroud)
现在我在jdata->'name'or上做 btree (jdata->'datetime')::cast,效果很好。
我也做 json_path_opsjdata->'array' @> '[{"name":"bla3"}]'真正的魅力所在。
我的问题是attr键可以在数组中的任何对象中,如果键存在,我关心记录,但是值几乎可以是任何东西。有没有办法查询这个?有没有办法索引它?我想做jdata->'array' @> '[{"attr": ?}]'或者也许? 'attr'可以在数组中以某种方式使用?
目前我正在考虑一个扫描键的触发器,然后将它移动到一个带有 true 或 false 或其他什么的标题,然后一个普通的 btree 将工作。有没有更好的办法?我需要在平均站点上编辑大约 50 万条记录才能添加这些值。
请给我指明一个方向。
SELECT *
FROM tbl
WHERE jdata->'array' @? '$ ? (exists (@."attr"))';
Run Code Online (Sandbox Code Playgroud)
您可以仅在外部嵌套级别或递归中查找键或值,以lax模式或不strict模式(模式)将数组抽象出来(取消嵌套)。我在小提琴中添加了查询变体来演示:
db<>在这里摆弄
jsonpath价值'$ ? (exists (@."attr"))'解释:
$...查看在左操作数中找到的每个值(在默认的“宽松”模式下)
?...运行以下测试
(exists (@."attr"))...是否存在名称为“attr”的键?
可以使用索引,或者使用默认值jsonb_ops:
CREATE INDEX tbl_jdata_array_idx ON tbl USING GIN ((jdata->'array'));
Run Code Online (Sandbox Code Playgroud)
或与jsonb_path_ops:
CREATE INDEX tbl_jdata_array_path_ops_idx ON tbl USING GIN ((jdata->'array') jsonb_path_ops);
Run Code Online (Sandbox Code Playgroud)
看:
有关的:
内置运算符的普通索引未涵盖该特定用例。
SELECT *
FROM tbl
WHERE EXISTS (
SELECT FROM jsonb_array_elements(jdata->'array') elem
WHERE elem ? 'attr'
);
Run Code Online (Sandbox Code Playgroud)
EXISTS因为我们希望每个符合条件的行一次,即使多个数组元素可以包含键。而且速度更快。
但是这个查询不能使用索引。
您可以在给定的 jsonb 记录数组中生成唯一键的文本数组 - 并将表达式包装到一个简单的IMMUTABLE函数中:
CREATE OR REPLACE FUNCTION jsonb_arr_record_keys(jsonb)
RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY (
SELECT DISTINCT k
FROM jsonb_array_elements($1) elem, jsonb_object_keys(elem) k
)';
COMMENT ON FUNCTION jsonb_arr_record_keys(jsonb) IS '
Generates text array of unique keys in jsonb array of records.
Fails if any array element is not a record!';
Run Code Online (Sandbox Code Playgroud)
然后根据这个函数创建一个 GIN 表达式索引:
CREATE INDEX tbl_special_idx ON tbl USING gin (jsonb_arr_record_keys(jdata->'array'));
Run Code Online (Sandbox Code Playgroud)
像这样查询,使用泛型数组 contains 运算符@>:
SELECT *
FROM tbl
WHERE jsonb_arr_record_keys(jdata->'array') @> '{attr}';
Run Code Online (Sandbox Code Playgroud)
现在可以有效地使用索引。
提供嵌套在数组 ( '{attr}') 中的键名。(您可以通过这种方式 ( '{attr1, attr2}') 或类似方式方便地检查多个键... )
dbfiddle在这里
有关的: