PostgreSQL JSONB 操作符详解

概述

PostgreSQL 提供了专门的 JSONB 类型和操作符,用于高效存储和查询 JSON 数据。JSONB 以二进制格式存储,支持索引和快速字段访问。


核心操作符

1. -> 操作符

作用: 提取 JSON 字段,返回 JSON 类型

语法:

sql 复制代码
jsonb_column -> 'key'

示例:

sql 复制代码
-- payload: {"name": "张三", "age": 25}
SELECT payload->'name' FROM users;
-- 结果: "张三" (JSON 字符串,带引号)

SELECT payload->'age' FROM users;
-- 结果: 25 (JSON 数字)

特点:

  • 返回 JSON 类型(保留引号、数据类型)
  • 适合继续链式操作

2. ->> 操作符

作用: 提取 JSON 字段,返回 TEXT 类型

语法:

sql 复制代码
jsonb_column ->> 'key'

示例:

sql 复制代码
-- payload: {"name": "张三", "age": 25}
SELECT payload->>'name' FROM users;
-- 结果: 张三 (纯文本,无引号)

SELECT payload->>'age' FROM users;
-- 结果: "25" (文本字符串)

特点:

  • 返回 TEXT 类型(去除引号)
  • 适合直接显示或字符串比较

3. #> 操作符

作用: 提取嵌套路径,返回 JSON 类型

语法:

sql 复制代码
jsonb_column #> '{key1,key2,key3}'

示例:

sql 复制代码
-- payload: {"user": {"address": {"city": "北京"}}}
SELECT payload#>'{user,address,city}' FROM users;
-- 结果: "北京" (JSON 字符串)

特点:

  • 支持多层嵌套访问
  • 返回 JSON 类型

4. #>> 操作符

作用: 提取嵌套路径,返回 TEXT 类型

语法:

sql 复制代码
jsonb_column #>> '{key1,key2,key3}'

示例:

sql 复制代码
-- payload: {"user": {"address": {"city": "北京"}}}
SELECT payload#>>'{user,address,city}' FROM users;
-- 结果: 北京 (纯文本)

特点:

  • 支持多层嵌套访问
  • 返回 TEXT 类型

对比总结

操作符 返回类型 用途 示例
-> JSON 单层提取,保持 JSON 格式 payload->'name'
->> TEXT 单层提取,转为文本 payload->>'name'
#> JSON 多层嵌套提取,保持 JSON 格式 payload#>'{a,b,c}'
#>> TEXT 多层嵌套提取,转为文本 payload#>>'{a,b,c}'

实际应用示例

场景 1:直接查询字段

sql 复制代码
-- 表结构
CREATE TABLE partner_level_lock_push_log (
    id BIGSERIAL PRIMARY KEY,
    payload JSONB NOT NULL,
    push_status SMALLINT DEFAULT 0
);

-- 查询特定字段
SELECT 
    id,
    payload->>'fiscalYear' as fiscal_year,
    payload->>'fiscalQuarter' as fiscal_quarter,
    payload->>'incentiveId' as incentive_id
FROM partner_level_lock_push_log
WHERE push_status IN (0, -1);

场景 2:条件过滤

sql 复制代码
-- 根据 JSON 字段过滤
SELECT * FROM partner_level_lock_push_log
WHERE payload->>'status' = 'locked';

-- 数值比较
SELECT * FROM partner_level_lock_push_log
WHERE (payload->>'age')::int > 25;

场景 3:批量提取并映射到对象

xml 复制代码
<!-- MyBatis XML -->
<select id="selectPendingLogs" resultType="java.lang.String">
    SELECT payload
    FROM ${tableName}
    WHERE push_status IN (0, -1)
    ORDER BY id ASC
    LIMIT #{limit}
</select>
java 复制代码
// Java 代码
List<String> payloadList = mapper.selectPendingLogs(tableName, 1000);

List<AnaplanPartnerLevelLockDo> dataList = new ArrayList<>();
for (String payload : payloadList) {
    AnaplanPartnerLevelLockDo lockDo = JSON.parseObject(payload, AnaplanPartnerLevelLockDo.class);
    dataList.add(lockDo);
}

tip:也可以不用转换,直接从数据库返回json object ,后续使用object

性能优化建议

✅ 推荐做法

  1. 直接查询 payload 字段

    sql 复制代码
    SELECT payload FROM table WHERE ...

    然后在 Java 中一次性反序列化。

  2. 使用 GIN 索引加速查询

    sql 复制代码
    CREATE INDEX idx_payload_gin ON table USING GIN (payload);
  3. 针对常用字段创建表达式索引

    sql 复制代码
    CREATE INDEX idx_fiscal_year ON table ((payload->>'fiscalYear'));

❌ 避免的做法

  1. 不要在 SQL 中逐个字段提取

    sql 复制代码
    -- 低效:数据库要做多次 JSON 解析
    SELECT 
        payload->>'field1',
        payload->>'field2',
        payload->>'field3',
        ...
    FROM table;
  2. 不要混合使用 JSON 和关系型字段

    • 如果某个字段需要频繁查询/排序,应该单独建列
    • JSONB 适合存储结构化但不常查询的数据

常见错误

错误 1:混淆 ->->>

sql 复制代码
-- 错误:返回 JSON 类型,无法直接比较
SELECT * FROM table WHERE payload->'status' = 'active';

-- 正确:返回 TEXT 类型
SELECT * FROM table WHERE payload->>'status' = 'active';

错误 2:嵌套路径格式错误

sql 复制代码
-- 错误:缺少花括号
SELECT payload#>'user,address,city' FROM table;

-- 正确:需要花括号
SELECT payload#>'{user,address,city}' FROM table;

错误 3:类型转换问题

sql 复制代码
-- 错误:文本比较
SELECT * FROM table WHERE payload->>'age' > 25;

-- 正确:显式转换
SELECT * FROM table WHERE (payload->>'age')::int > 25;

最佳实践

1. 简单场景:直接查 payload

sql 复制代码
-- 最简单最高效
SELECT payload FROM table WHERE push_status = 0;

Java 端反序列化一次即可。

2. 部分字段提取:只取需要的字段

sql 复制代码
SELECT 
    payload->>'fiscalYear' as fiscal_year,
    payload->>'incentiveId' as incentive_id
FROM table
WHERE push_status = 0;

适用于只需要少数字段的场景。

3. 复杂查询:结合索引

sql 复制代码
-- 创建索引
CREATE INDEX idx_status ON table ((payload->>'status'));

-- 利用索引查询
SELECT payload FROM table
WHERE payload->>'status' = 'locked';

总结

  • -> / ->>: 单层提取
  • #> / #>>: 多层嵌套提取
  • 箭头单数 (->, #>): 返回 JSON 类型
  • 箭头双数 (->>, #>>): 返回 TEXT 类型
  • 最佳实践 : 直接查询 payload 字段,在应用层反序列化
相关推荐
lv__pf3 小时前
redis【msb 2026金三银四redis上】
数据库·redis·缓存
布莱克6054 小时前
理解数据库聚簇索引:原理、优势与适用场景
数据库·mysql
牛企老板俱乐部4 小时前
广东机器人结构验证手板产业格局:深圳珠海东莞三城分析
大数据·人工智能
Keystone_Onion4 小时前
基于5大仓群路由算法的中大件美国海外仓降本架构与数据实测分析
大数据
buligbulig4 小时前
智能电网的数据底座:电力行业大数据治理路径解析
大数据
ltqvibe4 小时前
企业AI改造的四层路径:从点上应用到企业大脑
大数据·人工智能·本体语义平台·企业ai改造·数据打通·企业大脑·企业认知基础设施
anxiao_m4 小时前
园区数字孪生怎么搭建?主流方案与服务商深度对比
大数据·运维·人工智能
Nturmoils4 小时前
只面对一张表:KingbaseES 超表如何简化海量时序数据管理
数据库
starrocks_stella5 小时前
StarRocks 如何查询 Paimon 半结构化数据?Variant、Shredding 与 SQL 实践
数据库