RedisJSON 怎样只在字段不存在时写入
来源:17golang原创
时间:2026-10-17 23:00:42 447浏览 收藏
RedisJSON 的条件写入关键不在“字段名像不像新字段”,而在 JSONPath 是否命中了位置:NX 只在路径没有匹配时写入,XX 只在路径已经匹配时写入。要实现“字段不存在才补写”,通常选 JSON.SET key $.field value NX;要实现“只更新已有字段”,则选 JSON.SET key $.field value XX。
官方地址:https://redis.io/docs/latest/commands/JSON.SET/
下面的示例只围绕一个 RedisJSON 文档展开,重点看路径、条件和返回值的对应关系。命令中的 (nil) 表示条件没有满足或路径无法创建,不等于 Redis 服务异常。
NX 与 XX 到底判断什么
NX 与 XX 判断的是路径匹配结果,而不是简单判断 Redis 键是否存在。
| 条件 | 路径要求 | 适合的意图 | 条件不满足 |
|---|---|---|---|
NX | 路径没有匹配位置 | 首次创建、只补缺失字段 | 返回 (nil) |
XX | 路径至少匹配一个位置 | 只更新已有字段 | 返回 (nil) |
| 不带条件 | 按路径直接创建或替换 | 明确允许覆盖 | 由路径本身决定 |

例如文档中已有 $.profile.name,执行 JSON.SET user:1 $.profile.name "李四" NX 时,路径已经命中,NX 不会覆盖它;同一个路径配合 XX 才是更新语义。
用根路径 NX 创建一次性文档
当 Redis 键还不存在时,新 JSON 文档只能从根路径 $ 或旧式根路径 . 建立。根路径没有匹配位置,因此适合配合 NX 做“只初始化一次”。
# 第一次只在文档不存在时创建根对象
redis-cli JSON.SET user:100 $ '{"name":"小林","level":1}' NX
# 第二次仍然使用 NX,根路径已经命中,因此不会覆盖原文档
redis-cli JSON.SET user:100 $ '{"name":"新值","level":9}' NX
# 读取根文档,确认初始化值仍然保留
redis-cli JSON.GET user:100 $
预期语义是第一次返回 OK,第二次返回 (nil)。这里的关键是把“初始化整个文档”限制在根路径;如果把新键与 $.name 直接组合,RedisJSON 没有父文档可以承载这个成员。
用字段路径 NX 补写缺失成员
当父对象已经存在时,NX 可以用于补写最后一级、尚未出现的对象成员。它不会替你创建缺失的中间对象,所以 $.profile.nickname 能否成功,取决于 profile 是否已经是对象。
# 先准备一个已经存在的父对象
redis-cli JSON.SET user:101 $ '{"profile":{"name":"小周"}}'
# nickname 尚未命中,NX 允许补写最后一级成员
redis-cli JSON.SET user:101 $.profile.nickname '"zhou"' NX
# nickname 已经命中,再次使用 NX 会返回 nil,不覆盖原值
redis-cli JSON.SET user:101 $.profile.nickname '"changed"' NX
# 读取 profile,查看补写结果
redis-cli JSON.GET user:101 $.profile
这里要区分两件事:profile 是已存在的父对象,nickname 是待创建的最终成员。只有后一段缺失时,NX 才有机会返回 OK。
用 XX 更新已存在字段
如果业务要求“只有字段已经存在才允许更新”,应使用 XX。这样可以把拼写错误、数据结构不完整或初始化遗漏暴露为条件未满足,而不是静默增加一个新字段。
# 准备一个已有 status 字段的文档
redis-cli JSON.SET order:100 $ '{"status":"pending","retry":0}'
# status 已命中,XX 允许更新它
redis-cli JSON.SET order:100 $.status '"paid"' XX
# missing 字段没有命中,XX 拒绝这次写入
redis-cli JSON.SET order:100 $.missing '1' XX
# 读取 status,确认更新目标是已有字段
redis-cli JSON.GET order:100 $.status
XX 返回 (nil) 时,调用方可以选择记录“字段未初始化”、回退到初始化流程,或者把请求当作业务冲突处理。不要把所有 nil 都当成网络故障重试,否则重试不会改变路径命中条件。
新键、根路径与嵌套字段的创建边界
最容易混淆的是“最后一级成员可以创建”和“中间路径可以自动创建”并不是一回事。RedisJSON 可以在已有父对象中创建最终成员,但不会跨过不存在的中间对象。

| 数据状态 | 路径 | 推荐判断 | 结果重点 |
|---|---|---|---|
| 键不存在 | $ | NX | 可以创建整个根文档 |
| 父对象存在,最终成员不存在 | $.profile.nickname | NX | 可以补写最终成员 |
| 父对象不存在 | $.profile.nickname | 先初始化父对象 | 中间路径无法创建,通常返回 (nil) |
| 最终成员已经存在 | $.profile.nickname | XX | 可以更新;配合 NX 则拒绝覆盖 |
# 文档只有 name,没有 profile
redis-cli JSON.SET user:102 $ '{"name":"小赵"}'
# profile 这个中间对象不存在,不能直接跨层创建 nickname
redis-cli JSON.SET user:102 $.profile.nickname '"zhao"' NX
# 先建立父对象,再补写最终成员
redis-cli JSON.SET user:102 $.profile '{}' NX
redis-cli JSON.SET user:102 $.profile.nickname '"zhao"' NX
如果键本身不存在且路径不是根路径,RedisJSON 还会拒绝用嵌套路径直接建立新文档。工程上更稳妥的做法是把“根文档初始化”和“已有对象补字段”拆成两个明确的写入边界。
把返回值接入调用方决策
条件写入的返回值很简单:成功通常是 OK,条件不满足或路径无法创建时是 (nil),值或路径格式错误则是错误回复。调用方应按这三类分支处理。
# 用 shell 变量保留返回值,便于区分条件失败与命令错误
result=$(redis-cli JSON.SET user:101 $.profile.nickname '"new"' NX)
# 只把 nil 当成“目标路径已有值或暂时不可创建”
if [ "$result" = "(nil)" ]; then
echo "条件未满足:保留已有字段或补齐父对象"
elif [ "$result" = "OK" ]; then
echo "写入成功"
else
echo "命令或路径错误:${result}"
fi
在客户端库中,具体返回类型可能表现为字符串、布尔值或空值,但判断原则不变:先识别条件未满足,再决定是否走初始化、更新或冲突分支,不要在没有改变文档状态时无限重试。
常见问题
NX 能不能保证整个 Redis 键只写一次?
对根路径 $ 使用 NX,可以表达“这个 JSON 文档只初始化一次”。如果只对某个字段使用 NX,它保护的是该字段路径,不会阻止同一文档的其他字段被写入。
字段不存在时用 NX,为什么还是返回 nil?
先检查父对象是否存在、是否真的是对象,以及中间路径是否缺失。最终成员缺失可以创建,但中间对象不会自动补齐。
更新字段应该选 NX 还是 XX?
只更新已存在字段选 XX;只在字段不存在时补写选 NX。若允许无条件覆盖,则不要把条件失败误判成 Redis 故障。
JSON.SET 的路径写法应该用 $ 还是 .?
根路径可以使用 $ 或 .。新文章和新代码建议统一使用 $,嵌套字段用类似 $.profile.nickname 的 JSONPath 表达。
小结
记住一句话:NX 看路径没有命中,XX 看路径已经命中。新键从根路径初始化,已有父对象才能补最后一级成员,缺失的中间路径需要先单独建立。把这三条边界写进调用方分支,RedisJSON 的“只写一次”和“只更新已有字段”就不会混在一起。
-
104 收藏
-
141 收藏
-
256 收藏
-
238 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习