在 PostgreSQL 中使用非结构化数据在 JSONB 列中搜索
Search in JSONB column with unstructured data in PostgreSQL
我的 table 中有一个 JSONB 列,它在我的 PostgreSQL 数据库中存储非结构化数据。我需要搜索特定的键值对,但我不知道该键值的确切位置。
例如,如果我正在搜索
“name”: “John”
数据可能如下所示:
{
“id”: 1,
“name”: “John”
“cars”: []
}
但是,在另一行中,该键值对可能出现在数组或另一个对象(不在第一层)中
{
“id”: 1,
“students”:
[
{
“id”: 2,
“name”: “John”
}
]
}
有什么方法可以在不知道具体位置的情况下搜索特定的键值对吗?
我在 9.6 中能想到的唯一方法是创建一个递归遍历所有元素的函数和 returns JSON 值的“扁平化”视图。
create or replace function flatten(p_input jsonb)
returns table(key text, value text)
as
$$
begin
if jsonb_typeof(p_input) = 'array' then
return query
select f.*
from jsonb_array_elements(p_input) as a(element)
cross join flatten(a.element) f;
else
return query
select e.key, e.value #>> '{}'
from jsonb_each(p_input) as e(key, value)
where jsonb_typeof(e.value) not in ('object', 'array')
union all
select f.*
from jsonb_each(p_input) as t(key,value)
cross join flatten(t.value) as f
where jsonb_typeof(t.value) = 'object'
union all
select f.*
from jsonb_each(p_input) as t(key,value)
cross join jsonb_array_elements(t.value) as a(element)
cross join flatten(a.element) as f
where jsonb_typeof(t.value) = 'array';
end if;
end;
$$
language plpgsql;
那么你可以这样使用它:
select t.*
from the_table
where exists (select *
from flatten(t.the_column)
where t.key = 'name'
and t.value = 'John');
我的 table 中有一个 JSONB 列,它在我的 PostgreSQL 数据库中存储非结构化数据。我需要搜索特定的键值对,但我不知道该键值的确切位置。 例如,如果我正在搜索
“name”: “John”
数据可能如下所示:
{
“id”: 1,
“name”: “John”
“cars”: []
}
但是,在另一行中,该键值对可能出现在数组或另一个对象(不在第一层)中
{
“id”: 1,
“students”:
[
{
“id”: 2,
“name”: “John”
}
]
}
有什么方法可以在不知道具体位置的情况下搜索特定的键值对吗?
我在 9.6 中能想到的唯一方法是创建一个递归遍历所有元素的函数和 returns JSON 值的“扁平化”视图。
create or replace function flatten(p_input jsonb)
returns table(key text, value text)
as
$$
begin
if jsonb_typeof(p_input) = 'array' then
return query
select f.*
from jsonb_array_elements(p_input) as a(element)
cross join flatten(a.element) f;
else
return query
select e.key, e.value #>> '{}'
from jsonb_each(p_input) as e(key, value)
where jsonb_typeof(e.value) not in ('object', 'array')
union all
select f.*
from jsonb_each(p_input) as t(key,value)
cross join flatten(t.value) as f
where jsonb_typeof(t.value) = 'object'
union all
select f.*
from jsonb_each(p_input) as t(key,value)
cross join jsonb_array_elements(t.value) as a(element)
cross join flatten(a.element) as f
where jsonb_typeof(t.value) = 'array';
end if;
end;
$$
language plpgsql;
那么你可以这样使用它:
select t.*
from the_table
where exists (select *
from flatten(t.the_column)
where t.key = 'name'
and t.value = 'John');