PostgreSQL jsonb @>操作符疑问:为何包含判断返回false?
问题原因及修正方案
你的data字段存储的是JSONB数组,而PostgreSQL的@>(包含)操作符对数组的匹配规则是:左侧数组必须包含右侧数组的所有元素,且右侧必须也是JSONB数组类型。你当前传入右侧的是单个JSON对象,并非数组,因此类型不匹配,返回f。
修正方案1:将右侧对象包装为数组直接匹配
如果要验证整个数组是否包含指定元素(以数组形式传入),可以把右侧的单个对象包装成数组:
SELECT data::text, jsonb_typeof(data), jsonb_array_length(data), (data->0)::text, data @> '[{"role_id": "1", "user_name": "borrey"}]'::jsonb AS contains_self_array, data @> '[{"user_name":"borrey","role_id":"1"}]'::jsonb AS contains_manual_array FROM test_jsonb;
此查询会返回t,因为左侧数组包含右侧数组的唯一元素。
修正方案2:检查数组内元素是否匹配目标对象
如果需要验证数组中存在某个元素包含指定键值对,可以提取数组元素后单独匹配,或用EXISTS子查询遍历数组:
SELECT data::text, jsonb_typeof(data), jsonb_array_length(data), (data->0)::text, -- 直接匹配数组第一个元素 (data->0) @> (data->0) AS contains_self_element, (data->0) @> '{"user_name":"borrey","role_id":"1"}'::jsonb AS contains_manual_element, -- 通用方式:检查数组中是否有任意元素符合条件 EXISTS ( SELECT 1 FROM jsonb_array_elements(data) elem WHERE elem @> '{"user_name":"borrey","role_id":"1"}'::jsonb ) AS exists_matching_element FROM test_jsonb;
该方案更适合数组包含多个元素的场景,能灵活检查是否存在符合条件的元素。
补充说明
@>操作符的匹配规则严格依赖类型:
- 当左侧是JSONB对象时,右侧必须是JSONB对象,检查左侧对象是否包含右侧对象的所有键值对;
- 当左侧是JSONB数组时,右侧必须是JSONB数组,检查左侧数组是否包含右侧数组的所有元素(元素存在即可,不要求顺序)。
你之前的写法混淆了数组与对象的匹配场景,导致结果不符合预期。
内容的提问来源于stack exchange,提问作者Borrey
相关产品推荐
相关产品推荐

