-> 与 ->> 是什么
两个运算符都用于从 JSON 文档里取值,区别在返回类型:-> 返回 JSON 类型(字符串带双引号),->> 返回纯文本。要接着套 JSON 函数、做包含判断时用 ->;要和字符串比较、分组、展示时用 ->>。MySQL 从 5.7.13 起支持,PostgreSQL 的 jsonb 同样支持这一对写法。
基本信息
| -> 返回 | JSON / JSONB 类型,字符串值保留双引号 |
|---|---|
| ->> 返回 | 文本类型,字符串值去掉引号 |
| 路径写法 | MySQL 用 '$.key';PostgreSQL 用 'key' 或 '{key}' |
| 数组下标 | 两边都从 0 开始 |
| 比较场景 | 过滤与分组统一用 ->>,避免类型不匹配 |
| 索引 | 对 jsonb 建表达式索引要按 ->> 的文本形式建 |
两种取值方式
两种取值方式
-- MySQL 的路径写法
SELECT doc->'$.status' AS as_json, -- '"paid"':带引号的 JSON 字符串
doc->>'$.status' AS as_text -- 'paid':纯文本
FROM orders;
-- 过滤要用 ->>,否则与字符串比较会依赖隐式转换
SELECT * FROM orders WHERE doc->>'$.status' = 'paid';
-- 数组取元素:下标从 0 开始
SELECT doc->'$.tags[0]' AS first_tag FROM users;PostgreSQL 写法
PostgreSQL 写法
-- jsonb 列:路径不写 $ 前缀
SELECT doc->'status' AS as_json, -- "paid"
doc->>'status' AS as_text -- paid
FROM orders;
SELECT * FROM orders WHERE doc->>'status' = 'paid'; -- 文本比较
SELECT doc->'tags'->>0 AS first_tag FROM users; -- 数组元素
-- 表达式索引:表达式必须与查询谓词完全一致
CREATE INDEX idx_orders_status ON orders ((doc->>'status'));什么时候用哪一个
| 场景 | 用 -> | 用 ->> |
|---|---|---|
| 与字符串比较 | 类型不匹配,行为随版本变化 | 推荐,直接与文本比较 |
| 继续套 JSON 函数 | 推荐,保持 JSON 类型 | 需要再转回 JSON |
| GROUP BY 分组 | 分组值带引号不直观 | 推荐 |
| JSON 包含判断 | 直接传入 JSON 片段 | 需要先转回 JSON |
| 建索引 | jsonb 可建 GIN 索引 | 建表达式索引,按文本形式 |
典型使用场景
- 从 JSON 字段里取状态、渠道等标量值做过滤
- 取数组元素展示,例如取第一个标签
- 按 JSON 内部某个键分组统计
- 校验上报数据的字段是否齐全
- 给高频查询的 JSON 键建表达式索引
- 迁移期同时保留原始 JSON 文本与解析结果,便于比对
PostgreSQL 里 jsonb 与 text 直接比较会报 operator does not exist:doc->'status' = 'paid' 在 PG 中就属于这类错误,必须改成 ->>。这是跨库脚本最容易漏改的一处。
路径写错不会报错:键不存在时 MySQL 与 PostgreSQL 都返回 NULL,条件静默不命中。上线前先用一条已知存在的记录验证路径,别等报表空了才发现。