JSONB 字段中对象的 Postgresql 查询数组
Postgresql query array of objects in JSONB field
我在 postgresql 9.4 数据库中有一个 table,其中有一个名为 receivers 的 jsonb 字段。一些示例行:
[{"id": "145119603", "name": "145119603", "type": 2}]
[{"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "363058213", "name": "363058213", "type": 1}]
[{"id": "1427965764", "name": "1427965764", "type": 1}]
[{"id": "193623800", "name": "193623800", "type": 0}, {"id": "419955814", "name": "419955814", "type": 0}]
[{"id": "624635532", "name": "624635532", "type": 0}, {"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "791712670", "name": "791712670", "type": 0}]
[{"id": "895207852", "name": "895207852", "type": 0}]
[{"id": "144695994", "name": "144695994", "type": 0}, {"id": "384217055", "name": "384217055", "type": 0}]
[{"id": "1079725696", "name": "1079725696", "type": 0}]
我有一个 id 值列表,想 select 在 jsonb 字段的数组中包含具有该列表中任何值的对象的任何行。
这可能吗?我可以创建一个 GIN 索引来加快速度吗?
没有单一的操作,可以帮助你,但你有几个选择:
1. 如果要查询的 id 数量较少(且固定),可以使用多个包含运算符 @>
结合 or
; f.ex.:
where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]'
一个简单的 gin
索引可以帮助您处理此处的数据列。
2. 如果你有可变数量的 id(或者你有很多),你可以使用 json[b]_array_elements()
来提取数组的每个元素,建立一个 id 列表,然后使用任何包含运算符 ?|
:
查询它
select *
from jsonbtest
where to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?|
array['1884595530', '791712670'];
遗憾的是,您无法为包含子查询的表达式建立索引。如果你想索引它,你需要为它创建一个函数:
create function idlist_jsonb(jsonbtest)
returns jsonb
language sql
strict
immutable
as $func$
select to_json(array(select jsonb_array_elements(.data) ->> 'id'))::jsonb
$func$;
create index on jsonbtest using gin (idlist_jsonb(jsonbtest));
在此之后,您可以像这样查询 ID:
select *, jsonbtest.idlist_jsonb
from jsonbtest
where jsonbtest.idlist_jsonb ?| array['193623800', '895207852'];
注意:我在这里使用了dot notation / computed field,但你不必。
3. 但在这一点上,您不必坚持使用 json[b]:您有一个简单的文本数组,它受PostgreSQL 也是。
create function idlist_array(jsonbtest)
returns text[]
language sql
strict
immutable
as $func$
select array(select jsonb_array_elements(.data) ->> 'id')
$func$;
create index on jsonbtest using gin (idlist_array(jsonbtest));
并使用重叠数组运算符查询此计算域 &&
:
select *, jsonbtest.idlist_array
from jsonbtest
where jsonbtest.idlist_array && array['193623800', '895207852'];
注意:根据我的内部测试,后一种解决方案的计算成本高于 jsonb 变体,但实际上它比后者更快,一点。如果性能对您来说真的很重要,您应该同时测试两者。
我找到解决方法:
where data::text similar to '%("id": "145119603"|"id": "1884595530")%'
我在 postgresql 9.4 数据库中有一个 table,其中有一个名为 receivers 的 jsonb 字段。一些示例行:
[{"id": "145119603", "name": "145119603", "type": 2}]
[{"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "363058213", "name": "363058213", "type": 1}]
[{"id": "1427965764", "name": "1427965764", "type": 1}]
[{"id": "193623800", "name": "193623800", "type": 0}, {"id": "419955814", "name": "419955814", "type": 0}]
[{"id": "624635532", "name": "624635532", "type": 0}, {"id": "1884595530", "name": "1884595530", "type": 1}]
[{"id": "791712670", "name": "791712670", "type": 0}]
[{"id": "895207852", "name": "895207852", "type": 0}]
[{"id": "144695994", "name": "144695994", "type": 0}, {"id": "384217055", "name": "384217055", "type": 0}]
[{"id": "1079725696", "name": "1079725696", "type": 0}]
我有一个 id 值列表,想 select 在 jsonb 字段的数组中包含具有该列表中任何值的对象的任何行。
这可能吗?我可以创建一个 GIN 索引来加快速度吗?
没有单一的操作,可以帮助你,但你有几个选择:
1. 如果要查询的 id 数量较少(且固定),可以使用多个包含运算符 @>
结合 or
; f.ex.:
where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]'
一个简单的 gin
索引可以帮助您处理此处的数据列。
2. 如果你有可变数量的 id(或者你有很多),你可以使用 json[b]_array_elements()
来提取数组的每个元素,建立一个 id 列表,然后使用任何包含运算符 ?|
:
select *
from jsonbtest
where to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?|
array['1884595530', '791712670'];
遗憾的是,您无法为包含子查询的表达式建立索引。如果你想索引它,你需要为它创建一个函数:
create function idlist_jsonb(jsonbtest)
returns jsonb
language sql
strict
immutable
as $func$
select to_json(array(select jsonb_array_elements(.data) ->> 'id'))::jsonb
$func$;
create index on jsonbtest using gin (idlist_jsonb(jsonbtest));
在此之后,您可以像这样查询 ID:
select *, jsonbtest.idlist_jsonb
from jsonbtest
where jsonbtest.idlist_jsonb ?| array['193623800', '895207852'];
注意:我在这里使用了dot notation / computed field,但你不必。
3. 但在这一点上,您不必坚持使用 json[b]:您有一个简单的文本数组,它受PostgreSQL 也是。
create function idlist_array(jsonbtest)
returns text[]
language sql
strict
immutable
as $func$
select array(select jsonb_array_elements(.data) ->> 'id')
$func$;
create index on jsonbtest using gin (idlist_array(jsonbtest));
并使用重叠数组运算符查询此计算域 &&
:
select *, jsonbtest.idlist_array
from jsonbtest
where jsonbtest.idlist_array && array['193623800', '895207852'];
注意:根据我的内部测试,后一种解决方案的计算成本高于 jsonb 变体,但实际上它比后者更快,一点。如果性能对您来说真的很重要,您应该同时测试两者。
我找到解决方法:
where data::text similar to '%("id": "145119603"|"id": "1884595530")%'