PostgreSQL jsonb 字段查询操作符

FreeGuideOnline 最新 2026-07-05

sql -- 创建产品表,info 字段为 jsonb 类型 CREATE TABLE products ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, info JSONB );

-- 插入示例数据 INSERT INTO products (name, info) VALUES ('智能手机', '{"brand": "TechCorp", "price": 599, "tags": ["electronics", "mobile"], "specs": {"screen": 6.1, "storage": 128}}'), ('笔记本电脑', '{"brand": "ComputeX", "price": 1299, "tags": ["electronics", "computer"], "specs": {"screen": 15.6, "storage": 512}}'), ('耳机', '{"brand": "SoundMax", "price": 79, "tags": ["audio"]}');


## 基础抽取操作符

用于从 `jsonb` 中提取特定字段或路径的值,是日常查询中最常用的操作符。

### `->` 获取 jsonb 对象

通过键名返回一个 `jsonb` 对象(仍然是 JSON 类型)。

```sql
SELECT 
    name,
    info -> 'brand' AS brand_jsonb
FROM products;

结果中 brand_jsonb 列的值类似 "TechCorp",注意它是带引号的 JSON 字符串。

->> 获取文本值

-> 类似,但返回的是 text 类型(去掉了 JSON 的引号)。

SELECT 
    name,
    info ->> 'brand' AS brand_text
FROM products;

结果:TechCorp,可直接用于比较或字符串操作。

访问嵌套对象

可以通过链式调用访问深层字段:

-- 获取 specs 下的 storage 值
SELECT 
    name,
    info -> 'specs' ->> 'storage' AS storage_text
FROM products;

先通过 -> 拿到内层对象,再用 ->> 取出文本。

路径抽取操作符

当需要直接通过路径访问深层次键时,路径操作符更简洁。

#> 获取指定路径的 jsonb 对象

接受一个文本数组作为路径,返回路径指向的 jsonb 值。

SELECT 
    name,
    info #> '{specs, storage}' AS storage_jsonb
FROM products;

结果:128 仍为 jsonb。

#>> 获取指定路径的文本值

#> 类似,但返回 text 类型。

SELECT 
    name,
    info #>> '{specs, screen}' AS screen_text
FROM products;

JSON 包含与存在性操作符

用于判断 JSON 对象之间、键或数组元素的关系,非常适用于灵活的条件筛选。

@> 判断是否包含另一个 JSON 文档

左侧包含右侧的所有内容时返回 true

-- 查询 info 中包含 "brand": "TechCorp" 且 "price": 599 的产品
SELECT * FROM products
WHERE info @> '{"brand": "TechCorp", "price": 599}';

也可以用于数组元素:

-- 查询 tags 数组包含 "computer" 的产品
SELECT * FROM products
WHERE info @> '{"tags": ["computer"]}';

<@ 判断是否被另一个 JSON 文档包含

<@@> 的反向操作,即左侧是否被右侧包含。

SELECT '{"a":1}'::jsonb <@ '{"a":1, "b":2}'::jsonb; -- true

? 检查键或字符串是否作为顶层键存在

用于检查对象最外层是否包含某个键。

-- 查询 info 顶层存在 'brand' 键的产品
SELECT * FROM products
WHERE info ? 'brand';

?| 检查是否存在任意一个键

接受一个文本数组,对象中包含其中任意一个键时返回 true

-- 查询 info 中是否包含 'brand' 或 'color' 中的任意一个键
SELECT * FROM products
WHERE info ?| ARRAY['brand', 'color'];

?& 检查是否存在所有键

所有给定键都存在于对象顶层时才返回 true

-- 查询 info 中同时包含 'brand' 和 'price' 的产品
SELECT * FROM products
WHERE info ?& ARRAY['brand', 'price'];

常用的 jsonb 函数

除了操作符,PostgreSQL 还提供了一系列函数用于进一步处理数据。

jsonb_each() 展开键值对

jsonb 对象展开为键值对集合。

SELECT id, key, value
FROM products, jsonb_each(info);

通常与 LATERAL JOINFROM 中的逗号连用。

jsonb_array_elements() 展开数组

jsonb 数组展开为多行,每个元素一行。

SELECT name, tag
FROM products, jsonb_array_elements(info -> 'tags') AS tag;

jsonb_set() 更新 JSON 中的值

更新指定路径的值并返回新的 jsonb

-- 将所有产品的价格打 9 折后更新
UPDATE products
SET info = jsonb_set(info, '{price}', (info ->> 'price')::int * 0.9)::text::jsonb;

索引与性能优化

jsonb 字段上使用 GIN 索引可以极大加速包含、存在性等操作。

-- 创建 GIN 索引
CREATE INDEX idx_products_info ON products USING GIN (info);

GIN 索引支持以下操作符:@>, ?, ?|, ?&。对于路径查询(如 ->)如需加速,可创建表达式索引:

CREATE INDEX idx_products_brand ON products ((info ->> 'brand'));

实战示例

1. 找出所有包含 "electronics" 标签的产品名称

SELECT name FROM products
WHERE info -> 'tags' @> '"electronics"'::jsonb;

2. 获取所有产品的屏幕尺寸,并过滤掉没有 spec 的产品

SELECT 
    name,
    info #>> '{specs, screen}' AS screen
FROM products
WHERE info ? 'specs';

3. 统计每个品牌的产品数量

SELECT 
    info ->> 'brand' AS brand,
    COUNT(*) AS cnt
FROM products
GROUP BY brand;