JSONB嵌套数组查询-检查属性是否存在

时间:2019-01-17 10:43:22

标签: sql json postgresql jsonb

我想使用SQL检查JSONB列中属性的存在。

使用这是我可以检查属性是否等于值:

SELECT count(*) AS "count" FROM "table" WHERE column->'node' @> '[{"Attribute":"value"}]'

我使用什么语法检查Attribute是否存在?

2 个答案:

答案 0 :(得分:0)

通常,您将检查是否为空:

SELECT count(*) AS "count" FROM "table" 
WHERE column->'node'->'Attribute' is not null

答案 1 :(得分:0)

?运算符的意思是Does the string exist as a top-level key within the JSON value?,但是,您要检查嵌套嵌套json对象数组中是否存在键,因此无法直接使用该运算符。您必须取消嵌套数组。

样本数据:

create table my_table(id serial primary key, json_column jsonb);
insert into my_table (json_column) values
    ('{"node": [{"Attribute":"value"}, {"other key": 0}]}'),
    ('{"node": [{"Attribute":"value", "other key": 0}]}'),
    ('{"node": [{"Not Attribute":"value"}]}');

在横向联接中使用jsonb_array_elements()来查找键是否存在于数组的任何元素中:

select
    id,
    value,
    value ? 'Attribute' as key_exists_in_object
from my_table 
cross join jsonb_array_elements(json_column->'node')

 id |                 value                  | key_exists_in_object 
----+----------------------------------------+----------------------
  1 | {"Attribute": "value"}                 | t
  1 | {"other key": 0}                       | f
  2 | {"Attribute": "value", "other key": 0} | t
  3 | {"Not Attribute": "value"}             | f
(4 rows)

但这并不是您所期望的。您需要汇总数组的结果:

select
    id,
    json_column->'node' as array,
    bool_or(value ? 'Attribute') as key_exists_in_array
from my_table 
cross join jsonb_array_elements(json_column->'node')
group by id
order by id

 id |                   array                    | key_exists_in_array 
----+--------------------------------------------+---------------------
  1 | [{"Attribute": "value"}, {"other key": 0}] | t
  2 | [{"Attribute": "value", "other key": 0}]   | t
  3 | [{"Not Attribute": "value"}]               | f
(3 rows)

嗯,这看起来有点复杂。您可以使用以下功能使其更容易:

create or replace function key_exists_in_array(key text, arr jsonb)
returns boolean language sql immutable as $$
    select bool_or(value ? key)
    from jsonb_array_elements(arr)
$$;

select
    id,
    json_column->'node' as array,
    key_exists_in_array('Attribute', json_column->'node')
from my_table 

 id |                   array                    | key_exists_in_array 
----+--------------------------------------------+---------------------
  1 | [{"Attribute": "value"}, {"other key": 0}] | t
  2 | [{"Attribute": "value", "other key": 0}]   | t
  3 | [{"Not Attribute": "value"}]               | f
(3 rows)