PostgreSQL教程 -》数据类型 -》jsonb 包含和存在
最新学讯:近期OCP认证正在报名中,因考试人员较多请尽快报名获取最近考试时间,报名费用请联系在线老师,甲骨文官方认证,报名从速!
我要咨询8.14.3. jsonb 包含和存在
测试包含是jsonb的一种重要能力。对 json类型没有平行的功能集。包含测试会测试一个 jsonb文档是否被包含在另一个文档中。除了特别注解 之外,这些例子都会返回真:
-- 简单的标量/基本值只包含相同的值:
SELECT '"foo"'::jsonb @> '"foo"'::jsonb;
-- 右边的数字被包含在左边的数组中:
SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb;
-- 数组元素的顺序没有意义,因此这个例子也返回真:
SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb;
-- 重复的数组元素也没有关系:
SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb;
-- 右边具有一个单一键值对的对象被包含在左边的对象中:
SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb;
-- 右边的数组不会被认为包含在左边的数组中,
-- 即使其中嵌入了一个相似的数组:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb; -- 得到假
-- 但是如果同样也有嵌套,包含就成立:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;
-- 类似的,这个例子也不会被认为是包含:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb; -- 得到假
-- 包含一个顶层键和一个空对象:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;
一般原则是被包含的对象必须在结构和数据内容上匹配包含对象,这种匹配 可以是从包含对象中丢弃了不匹配的数组元素或者对象键值对之后成立。但 是记住做包含匹配时数组元素的顺序是没有意义的,并且重复的数组元素实 际也只会考虑一次。
结构必须匹配的一般原则有一种特殊情况,一个数组可以包含一个基本值:
-- 这个数组包含基本字符串值:
SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb;
-- 反之不然,下面的例子会报告“不包含”:
SELECT '"bar"'::jsonb @> '["bar"]'::jsonb; -- 得到假
jsonb还有一个存在操作符,它是包含的一种 变体:它测试一个字符串(以一个text值的形式给出)是否出 现在jsonb值顶层的一个对象键或者数组元素中。除非特别注解, 下面这些例子返回真:
-- 字符串作为一个数组元素存在:
SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar';
-- 字符串作为一个对象键存在:
SELECT '{"foo": "bar"}'::jsonb ? 'foo';
-- 不考虑对象值:
SELECT '{"foo": "bar"}'::jsonb ? 'bar'; -- 得到假
-- 和包含一样,存在必须在顶层匹配:
SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar'; -- 得到假
-- 如果一个字符串匹配一个基本 JSON 字符串,它就被认为存在:
SELECT '"foo"'::jsonb ? 'foo';
当涉及很多键或元素时,JSON 对象比数组更适合于做包含或存在测试, 因为它们不像数组,进行搜索时会进行内部优化,并且不需要被线性搜索。
提示
由于 JSON 的包含是嵌套的,因此一个恰当的查询可以跳过对子对象的显式选择。 例如,假设我们在顶层有一个doc列包含着对象,大部分对象 包含着tags域,其中有子对象的数组。这个查询会找到其中出现了 同时包含"term":"paris"和"term":"food"的子对象 的项,而忽略任何位于tags数组之外的这类键:
SELECT doc->'site_name' FROM websites
WHERE doc @> '{"tags":[{"term":"paris"}, {"term":"food"}]}';
可以用下面的查询完成同样的事情:
SELECT doc->'site_name' FROM websites
WHERE doc->'tags' @> '[{"term":"paris"}, {"term":"food"}]';
但是后一种方法灵活性较差,并且常常也效率更低。
在另一方面,JSON 的存在操作符不是嵌套的:它将只在 JSON 值的顶层 查找指定的键或数组元素。
第 9.15 节中记录了多个包含和存在操作符,以及 所有其他 JSON 操作符和函数。