1、指令速查
JSON.ARRPOP <key> [path [index]]
key:要修改的 Redis 键
path(可省略,默认
$
):JSONPath,可用..
/[*]
多路径匹配index(可省略,默认
-1
):要弹出的位置0
→ 头元素-1
→ 尾元素(等同于栈/队列 pop)- 其他负值 → 从末尾倒数
- 越界会被自动钳位到数组两端
- 空数组返回
null
返回值:与路径一一对应的被弹出元素;若路径不是数组 → nil
。
时间复杂度
- 单路径且弹出尾部 → O(1)
- 其他情况(头部 / 中间 / 多路径)→ O(N) ,N 为数组长度
2、核心优势
- 原子性:读 + 删一步到位,避免并发脏写
- 网络极简:只需一次 RTT
- 读写对等:返回值就是被删元素,可立即写入别处或计算
- 队列 / 栈场景天然契合:尾弹 (
index = -1
) = Stack;头弹 (index = 0
) = Queue
3、CLI 实战:耳机产品的 max_level
管理
3.1 创建数据
JSON.SET key $ '[{"name":"Healthy","max_level":[60,70,80]},
{"name":"Noisy","max_level":[80,90,100,120]}]'
3.2 弹出第二个产品的首个 max_level
redis> JSON.ARRPOP key $.[1].max_level 0
1) "80"
数组变为 [90,100,120]
,同时我们拿到了被删除的 80
。
3.3 再 Tail-Pop
redis> JSON.ARRPOP key $.[1].max_level # index 默认为 -1
1) "120"
现在数组仅剩 [90,100]
。
4、跨语言示例
Python(redis-py ≥ 5.0)
from redis import Redis
r = Redis(decode_responses=True)
popped = r.execute_command(
"JSON.ARRPOP", "key", "$.[1].max_level", 0
)
print(popped) # ["80"]
Node.js(@redis/client)
import { createClient } from 'redis';
const cli = createClient(); await cli.connect();
const [pop] = await cli.json.arrPop('key', '$.[1].max_level', -1);
console.log(pop); // 120
Go(go-redis/v9)
popped, _ := rdb.Do(ctx, "JSON.ARRPOP",
"key", "$.[0].max_level", -1).StringSlice()
log.Println(popped[0]) // "80"
5、典型应用场景
场景 | 玩法 |
---|---|
任务队列 | Workers:ARRPOP tasks $.queue 0 → 取出并删除头任务 |
缓存逐出策略 | 列表存最近记录,长度 > limit 时先 ARRPOP key $.list 0 再 ARRAPPEND |
移动元素 | ARRPOP src + ARRAPPEND dst 可原子搬迁(用 Lua/事务更稳) |
限流 | 每次写前 ARRLEN ,超限则 ARRPOP 头部旧数据 |
6、性能&陷阱
- 优先尾弹:尾部
ARRPOP
→ O(1),头/中间 O(N) - 多路径慎用:
$..array
会对每个匹配执行弹出,整体 O(N) - 空数组/不存在:返回
null
,注意判空 - 并发栈/队列:多个客户端同时
ARRPOP
尾部仍是安全的,但若需要一次弹出并插入别的键建议 Lua 脚本或MULTI
保证一致性
7、与数组家族指令的协同
ARRAPPEND
/ARRINSERT
:弹后再插,重排元素ARRLEN
:弹前统计,判断是否已空ARRINDEX
:先查后弹,删除指定值ARRTRIM
(下一篇):批量裁剪 vs 单条弹出
8、结语
至此,RedisJSON 对数组的增(APPEND / INSERT)、查(INDEX / LEN)、**删(POP)**已全部解锁。JSON.ARRPOP
通过原子弹出让你在队列、限流与实时数据清洗场景中如虎添翼。下一篇,我们将迎来本系列终章——JSON.ARRTRIM
,聚焦批量裁剪与窗口化数组,敬请期待!