Redis JSON 查询怎样限制返回字段
来源:17golang原创
时间:2026-11-07 21:36:14 312浏览 收藏
Redis JSON 查询要限制返回字段,核心不是给 JSON.GET 传一个 SQL 式的字段列表,而是把需要的字段写成 JSONPath 参数。例如只读取用户昵称和城市,可以使用 JSON.GET profile:demo $.nickname $.city。这样 Redis 只按指定路径取值,调用方再按照返回形状解包。
我在设计这类查询时会先把“读取哪些字段”和“接口最终允许暴露哪些字段”分开。JSON.GET 负责路径读取,接口层仍要负责字段白名单、权限和响应版本;不能因为命令没有取到 secret_note,就把它当成完整的访问控制。
Redis 官方地址:https://redis.io/
先把完整 JSON 和目标字段拆开
先准备一个结构稍微真实的文档:顶层有用户标识和昵称,profile 里有城市与语言偏好,同时放入一个不应该进入普通列表响应的字段。本文只讨论查询路径,不把命令当作本机执行记录。
# 使用独立示例键写入一份带嵌套对象的 JSON 文档
redis-cli JSON.SET 'profile:demo' '$' '{"user_id":42,"nickname":"lin","profile":{"city":"Hangzhou","locale":"zh-CN"},"secret_note":"internal-only"}'
# 先按路径读取完整文档,便于对照字段位置;生产接口不要默认返回内部字段
redis-cli JSON.GET 'profile:demo' '$'
这份文档里,$.user_id 与 $.nickname 是顶层路径,$.profile.city 是嵌套路径。若业务只需要列表展示,目标集合可以是前三个公开字段,而不是整个 JSON 文档。

用 JSONPath 读取指定字段
JSON.GET 的语法允许在键名后写一个或多个路径。新代码优先使用根路径形式:$.nickname、$.profile.city。路径越具体,返回目标越明确,也更容易在接口代码中建立字段白名单。
# 只读取两个公开字段,不把 secret_note 放进响应 redis-cli JSON.GET 'profile:demo' '$.nickname' '$.profile.city' # 只读取一个嵌套字段,适合详情接口中的局部信息 redis-cli JSON.GET 'profile:demo' '$.profile.locale'
这里的“限制返回字段”是路径级读取:它限制的是 JSON.GET 选中的节点,不会修改 Redis 中保存的文档,也不会自动删除其他字段。若后续要把结果返回给前端,应用层仍应把允许字段映射到单独的响应对象。
不要把 JSON.GET key $.profile.* 当成稳定的接口契约。通配路径适合一次读取同一对象下的一组动态字段,但字段新增、返回数量变化和客户端解包方式都会受到影响;对稳定的公开接口,明确列出路径更容易做变更评审。
多路径返回与旧路径语法要分开看
同一条 JSON.GET 可以接收多个路径。JSONPath 形式的多路径查询会保留路径与结果之间的对应关系,调用方不应只按数组下标猜字段。如果历史代码使用 .nickname 这类 legacy path,要先确认客户端和服务端都按兼容形状处理,再决定是否迁移到 $. 根路径。
# 多路径查询:显式列出需要的字段,应用层按路径名解包 redis-cli JSON.GET 'profile:demo' '$.nickname' '$.profile.city' # 兼容旧路径写法:迁移前不要把返回形状与 JSONPath 结果混用 redis-cli JSON.GET 'profile:demo' '.nickname' '.profile.city'
这两种写法的重点不是“哪一个更短”,而是返回形状和客户端约定是否一致。Redis 官方命令文档把 JSON.GET 描述为按一个或多个路径获取 JSON 序列化值;因此,调用方应该把返回结果当作协议的一部分记录下来,不要凭经验把所有版本、客户端的结果都当成同一种 JSON。

在 Go 客户端中按字段名解包
如果服务是 Go 写的,我会把 Redis 返回值先保留为字节,再解到明确的结构或映射中。关键点是:不要依赖多路径的传入顺序来绑定业务字段,也不要把任意 JSON 直接透传给前端。
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/redis/go-redis/v9"
)
type PublicProfile struct {
Nickname string `json:"nickname"`
City string `json:"city"`
}
func loadPublicProfile(ctx context.Context, client *redis.Client) (PublicProfile, error) {
// 明确列出公开路径,避免把内部字段当成接口响应的一部分。
raw, err := client.Do(ctx, "JSON.GET", "profile:demo", "$.nickname", "$.profile.city").Result()
if err != nil {
return PublicProfile{}, fmt.Errorf("读取 Redis JSON 失败: %w", err)
}
// 多路径结果的具体外形由服务端路径语法和客户端解码策略共同决定,先解为通用对象。
var byPath map[string]json.RawMessage
if err := json.Unmarshal([]byte(fmt.Sprint(raw)), &byPath); err != nil {
return PublicProfile{}, fmt.Errorf("解析 JSON.GET 返回值失败: %w", err)
}
var profile PublicProfile
if err := json.Unmarshal(byPath["$.nickname"], &profile.Nickname); err != nil {
return PublicProfile{}, fmt.Errorf("解析昵称失败: %w", err)
}
if err := json.Unmarshal(byPath["$.profile.city"], &profile.City); err != nil {
return PublicProfile{}, fmt.Errorf("解析城市失败: %w", err)
}
return profile, nil
}
这段代码重点展示边界,不是完整可运行项目:不同 go-redis 版本、RESP 设置和 RedisJSON 返回形状可能需要调整解码层。生产代码应该为缺少路径、null、类型变化和键不存在分别定义处理策略,并为字段映射写单元测试。
空值、路径错误和查询成本怎样判断
排查“为什么没有返回字段”时,我会按键、路径、类型三层看,而不是马上改成通配符:
| 现象 | 优先判断 | 处理方向 |
|---|---|---|
| 键不存在 | 业务键名或过期策略是否正确 | 记录键角色,不把不存在当成空对象 |
| 路径没有值 | JSONPath 拼写、大小写、嵌套层级 | 用一条明确路径对照文档结构 |
| 类型解析失败 | 字段是否从字符串变成数字、数组或 null | 固定响应类型并处理迁移期数据 |
| 返回过大 | 是否读取了根节点或宽泛通配路径 | 拆成明确路径,按接口需要取字段 |
JSON.GET 的官方命令说明给出的复杂度与路径评估和值大小有关,不能把“只取两个字段”理解成固定的零成本操作。对象很大、路径命中数组或一次传入很多路径时,仍需按真实数据量评估延迟和网络响应大小。本文不虚构压测数字。
# 用一个明确路径做最小排查,避免一开始就使用根节点或通配符 redis-cli JSON.GET 'profile:demo' '$.profile.city' # 查看键的类型;类型不对时先修写入约定,不要直接删除未知数据 redis-cli TYPE 'profile:demo'
把字段白名单变成可维护约定
最终可以把查询约定收敛成四条:
- 接口响应需要什么,就在 JSON.GET 中列出什么路径;不以“先取完整文档再过滤”作为默认方案。
- 对外字段使用稳定的路径名映射,Go、JavaScript 等客户端不要依赖返回数组顺序。
- 路径读取和权限控制分层:字段白名单、租户检查、日志脱敏仍由业务服务负责。
- 新增字段先兼容旧客户端,改变字段类型或嵌套层级时更新响应版本和测试样例。
这样处理后,Redis JSON 既保留了文档结构的灵活性,又不会让查询语句承担接口协议、授权和版本迁移的全部责任。
JSON.GET 能像 SQL 一样写字段别名吗?
不能把它当作 SQL 投影语法。JSON.GET 选择 JSONPath,字段改名和响应组装应放在应用层。
只查询一个字段还要写 JSONPath 吗?
建议写明确的根路径,例如 $.nickname,这样嵌套关系和返回意图更清楚。
路径不存在时是不是一定报错?
不应把路径未命中、键不存在和类型错误混为一谈。应用层要根据命令返回值、键生命周期和数据契约分别处理。
-
370 收藏
-
496 收藏
-
246 收藏
-
322 收藏
-
170 收藏
-
295 收藏
-
245 收藏
-
367 收藏
-
136 收藏
-
225 收藏
-
392 收藏
-
307 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习