PostgreSQL中JSONB操作符@?与@@有何差异?为何返回结果不同?
PostgreSQL中
@?和@@ JSONB操作符的差异解析 核心本质差异
@?:等价于jsonb_path_exists(),作用是检查JSON路径表达式是否能匹配到至少一个节点。只要路径能找到符合条件的非空节点集合,就返回true。@@:等价于jsonb_path_match(),要求路径表达式必须返回单个布尔值,而非节点集合。只有当表达式结果为true时才返回true;若返回节点集合或其他非单个布尔值,操作符会返回false(直接调用jsonb_path_match()不符合要求会报错)。
结合测试案例分析
@?返回t的原因:
路径$ ?(@.email.main == "hi@example.net")筛选出了符合条件的顶层JSON对象,匹配到了有效节点,因此@?返回t。david=# SELECT '{ "email": { "main": "hi@example.net" } }' @? '$ ?(@.email.main == "hi@example.net")'; ?column? ---------- t@@直接用相同路径返回f的原因:
该路径返回的是包含顶层对象的节点集合,不是单个布尔值,不符合@@的约束,因此返回f。直接调用jsonb_path_match()会明确报错ERROR: single boolean result is expected,直观体现了@@的要求。david=# SELECT '{ "email": { "main": "hi@example.net" } }' @@ '$ ?(@.email.main == "hi@example.net")'; ?column? ---------- fexists()的正确用法:
你用jsonb_path_match('...', 'exists($ ?(...))')能返回t,是因为exists()将节点集合转换为了单个布尔值。但@@用同样写法返回f,是因为路径里的$多余了——?已经是相对于顶层对象的筛选,正确写法应去掉$:david=# SELECT '{ "email": { "main": "hi@example.net" } }' @@ 'exists(?(@.email.main == "hi@example.net"))'; ?column? ---------- t更简洁的写法是直接使用布尔表达式(路径直接返回单个布尔值):
david=# SELECT '{ "email": { "main": "hi@example.net" } }' @@ '@.email.main == "hi@example.net"'; ?column? ---------- t
总结
- 验证是否存在匹配节点时,用
@?或jsonb_path_exists(); - 验证表达式直接返回true时,用
@@或jsonb_path_match(),确保路径返回单个布尔值,或用exists()将匹配结果转换为布尔值(注意路径写法)。
内容的提问来源于stack exchange,提问作者theory
相关产品推荐
相关产品推荐

