在 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');

Online example