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 字段,在应用层反序列化
相关推荐
旧曲重听12 小时前
为什么现在 RAG 越少越少提及了
数据库·程序人生·职场和发展·agent
2501_941982052 小时前
企业微信私域流量运营:如何利用RPA技术构建高效的社群自动化管理系统
大数据·人工智能·机器人·自动化·企业微信·rpa
Zhu7582 小时前
使用腾讯CNB构建Hadoop定制容器镜像
大数据·hadoop·分布式
Nturmoils2 小时前
订单查询丢数据,查了半天原来是 WHERE 惹的祸
数据库·后端
ATA88882 小时前
数据库管理工具的数据安全机制对比:权限管控与审计
数据库·人工智能·数据分析·数据库管理
麦聪聊数据3 小时前
业务自助取数(下):安全可控前提下,实现取数效率百倍提升
数据库·sql
2501_915716723 小时前
Repository-学习指南_小白版
数据库·人工智能
snpgroupcn3 小时前
SAP实施风险管控注意事项:四大风险域与防范策略
前端·数据库·人工智能
TTBIGDATA3 小时前
【Ambari Plus】13.Spark 安装
大数据·hadoop·分布式·spark·ambari·sqoop·ambari plus