无论键如何,按值查询 postgres jsonb

Posted

技术标签:

【中文标题】无论键如何,按值查询 postgres jsonb【英文标题】:Query postgres jsonb by value regardless of keys 【发布时间】:2016-03-27 17:24:38 【问题描述】:

我想获取所有记录,其中 jsonb 字段中的任何 value 包含文本,无论键如何。

例如:字段包含 json k1: 'hello', k2: 'world'。我想通过文本“你好”来获得这条记录。我不关心键或任何 json 结构,只关心值。

一个肮脏的技巧是将字段转换为 varchar where jsonb_field::varchar like ...,但这很丑陋,它也会匹配键和 。

另一个肮脏的黑客看起来像这样:

SELECT * FROM mytable AS m1 WHERE (
  SELECT string_agg(value, '') FROM jsonb_each_text( (SELECT name FROM mytable AS m2 WHERE m1.id= m2.id)::jsonb ) 
) LIKE '%whatever%';

但它也很丑。

我该怎么做?

【问题讨论】:

【参考方案1】:

对于简单的 JSON,您可以使用更合适的查询,例如

select * 
from mytable t 
where exists (
  select 1 
  from jsonb_each_text(t.jsonbfield) j 
  where j.value = 'hello');

它适用于您示例中的 JSON,但不适用于更复杂的 JSON,例如 "a":"hello","b":1,"c":"c":"world"

我可以提议创建像这样的存储函数

create or replace function jsonb_enum_values(in jsonb) returns setof varchar as $$
begin
  case jsonb_typeof($1)
    when 'object' then
      return query select jsonb_enum_values(j.value) from jsonb_each($1) j;
    when 'array' then
      return query select jsonb_enum_values(a) from jsonb_array_elements($1) as a;
    else
      return next $1::varchar;
  end case;
end
$$ language plpgsql immutable;

列出所有值,包括递归对象(由您决定如何处理数组)。

这是用法示例:

with t(x) as (
  values
    ('"a":"hello","b":"world","c":1,"d":"e":"win","f":"amp"'::jsonb),
    ('"a":"foo","b":"world","c":2'),
    ('"a":["b":"win","c":"amp","hello"]'),
    ('["a":"win"]'),
    ('["win","amp"]'))
select * 
from t 
where exists (
  select *
  from jsonb_enum_values(t.x) j(x) 
  where j.x = '"win"');

注意字符串值的双引号。

【讨论】:

如果我的 json 包含一个数组值,它就失败了。 @DeepakKumarPadhy 感谢您的关注。更新了函数和示例。 我觉得你的存储过程可以解决我的问题(***.com/questions/43252423/…)。我不确定这是否是最优化的方式,对我的问题有任何建议。 @DeepakKumarPadhy 最优化的方法是使用真正的关系模型而不是 JSON 列。简而言之:如果您打算按 JSON 列的内容搜索数据 - 不要使用 JSON :) 可能这就是为什么您仍然没有回答另一个问题的原因。你正在使用烦人但很受欢迎的anti-pattern

以上是关于无论键如何,按值查询 postgres jsonb的主要内容,如果未能解决你的问题,请参考以下文章

如何将postgres jsonb字段的属性插入键值表?

Postgres jsonb null vs 空对象查询性能

如何在 Vapor/Fluent 中正确查询 Postgres JSONB 字段

Postgres:在递归合并函数中删除 jsonb 键

如何根据postgres的jsonb列的where条件(无本机查询)使用jpa在spring boot中选择数据?

Postgres:查询多个jsonb字段