登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

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 文档。

Redis JSON 文档与 JSONPath 目标字段的静态结构说明图
静态结构说明图:完整 Redis JSON 文档经过 JSON.GET 与 JSONPath 选择后,只返回正文约定的目标字段;这不是截图,也不是运行证据。

用 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。

Redis JSON 多路径查询与返回形状差异的静态结构说明图
静态结构说明图:JSONPath 多路径和 legacy path 都是读取路径,但应用层需要分别处理路径键映射与兼容返回形状;这不是命令行截图。

在 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,这样嵌套关系和返回意图更清楚。

路径不存在时是不是一定报错?

不应把路径未命中、键不存在和类型错误混为一谈。应用层要根据命令返回值、键生命周期和数据契约分别处理。

官方参考:JSON.GET 命令文档、Redis JSON 数据类型文档。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>