RedisJSON 技术揭秘(五)`JSON.ARRPOP` 原子弹出 & 修改数组的终极手段

1、指令速查

text 复制代码
JSON.ARRPOP <key> [path [index]]
  • key:要修改的 Redis 键

  • path (可省略,默认 $):JSONPath,可用 .. / [*] 多路径匹配

  • index (可省略,默认 -1):要弹出的位置

    • 0 → 头元素
    • -1 → 尾元素(等同于栈/队列 pop)
    • 其他负值 → 从末尾倒数
    • 越界会被自动钳位到数组两端
    • 空数组返回 null

返回值 :与路径一一对应的被弹出元素;若路径不是数组 → nil

时间复杂度

  • 单路径且弹出尾部O(1)
  • 其他情况(头部 / 中间 / 多路径)→ O(N) ,N 为数组长度

2、核心优势

  1. 原子性:读 + 删一步到位,避免并发脏写
  2. 网络极简:只需一次 RTT
  3. 读写对等:返回值就是被删元素,可立即写入别处或计算
  4. 队列 / 栈场景天然契合 :尾弹 (index = -1) = Stack;头弹 (index = 0) = Queue

3、CLI 实战:耳机产品的 max_level 管理

3.1 创建数据

bash 复制代码
JSON.SET key $ '[{"name":"Healthy","max_level":[60,70,80]},
                 {"name":"Noisy","max_level":[80,90,100,120]}]'

3.2 弹出第二个产品的首个 max_level

bash 复制代码
redis> JSON.ARRPOP key $.[1].max_level 0
1) "80"

数组变为 [90,100,120],同时我们拿到了被删除的 80

3.3 再 Tail-Pop

bash 复制代码
redis> JSON.ARRPOP key $.[1].max_level    # index 默认为 -1
1) "120"

现在数组仅剩 [90,100]

4、跨语言示例

Python(redis-py ≥ 5.0)

python 复制代码
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)

js 复制代码
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)

go 复制代码
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 0ARRAPPEND
移动元素 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,聚焦批量裁剪与窗口化数组,敬请期待!