news 2026/9/15 18:35:54

DiceDB JSON.ARRAPPEND 命令详解:向 JSON 数组尾部追加元素

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DiceDB JSON.ARRAPPEND 命令详解:向 JSON 数组尾部追加元素

DiceDB JSON.ARRAPPEND 命令详解:向 JSON 数组尾部追加元素

【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb

JSON.ARRAPPEND是 DiceDB 中 DiceDBJSON 模块提供的原生 JSON 命令之一,用于向指定 JSON 文档中某个路径所指向的数组末尾追加一个或多个 JSON 值,并返回追加后数组的新长度。本文以仓库中的官方命令文档 JSON.ARRAPPEND.md 为核心骨架,结合 DiceDB 的命令注册、求值器实现与测试用例,完整讲解其语法、参数、返回值、错误语义与底层执行原理,读者可以据此在 DiceDB 中正确、高效地完成 JSON 数组的动态扩展操作。

命令概述

DiceDB 是一个开源、低延迟的键值引擎(low-latency key/value engine),通过 DiceDBJSON 模块提供原生的 JSON 数据能力。JSON.ARRAPPEND正是这套 JSON 命令体系中的数组追加原语,与JSON.SETJSON.GETJSON.ARRLENJSON.ARRINSERTJSON.ARRPOP等命令配合,可以在不读取、反序列化整个文档的前提下,对嵌套 JSON 数组进行就地修改。

从命令注册表看,该命令被标记为已迁移(IsMigrated: true),其元数据定义在 internal/eval/commands.go:

jsonarrappendCmdMeta = DiceCmdMeta{ Name: "JSON.ARRAPPEND", Info: `JSON.ARRAPPEND key [path] value [value ...] Returns an array of integer replies for each path, the array's new size, or nil, if the matching JSON value is not an array.`, Arity: -3, IsMigrated: true, NewEval: evalJSONARRAPPEND, }

Arity: -3表示该命令至少需要 3 个参数(key、path、至少一个 value),且参数个数可变;实际执行逻辑由evalJSONARRAPPEND函数承担(见下文"源码级实现剖析")。

语法

JSON.ARRAPPEND <key> <path> <json_value> [<json_value> ...]
  • <key>:必填,要操作的键。
  • <path>:必填,指向 JSON 文档中数组位置的 JSONPath 表达式。
  • <json_value>:必填,一个或多个要追加的 JSON 值,可重复传入多个。

参数说明

参数类型说明
keyString存储 JSON 文档的键名。
pathStringJSONPath 表达式,用于定位 JSON 文档中数组所在的位置。
json_valueJSON一个或多个要追加到数组末尾的 JSON 值。这些值必须是合法的 JSON 数据类型,例如字符串、数字、对象、数组、布尔值或null

需要特别强调的是,json_value是按JSON 字面量解析的:追加普通字符串时必须带引号(如"cherry"),追加对象/数组时使用{...}/[...]字面量。解析工作由底层实现调用sonic.UnmarshalString完成(见 internal/eval/store_eval.go),因此任何非法 JSON 输入都会直接报错。

返回值

  • Integer:追加操作完成后数组的新长度。
  • 当使用递归 JSONPath(如$..)一次匹配多个数组时,返回由各数组新长度组成的整数数组;其中被匹配到但不是数组的节点,对应位置返回nil(该行为在官方文档的"Return Value"一节未展开,但已被源码与测试明确证实,详见下文)。

行为语义

JSON.ARRAPPEND执行时,会将指定的 JSON 值依次追加到key下 JSON 文档中path所指向数组的末尾。若路径不存在或路径指向的值不是数组,命令会报错;若键不存在,命令报错(详见下文错误处理,其中文档描述与当前源码实现存在一处细微差异,已在实现剖析中说明)。

该命令具备以下关键语义:

  • 就地修改:数组元素是追加到目标数组的尾部,原有元素顺序与内容保持不变。
  • 支持一次追加多个值:多个json_value按命令行给定的先后顺序依次入列。
  • 支持多路径匹配:当 JSONPath 使用递归下降语法(如$..score)时,会对所有匹配到的数组执行追加。

错误处理

官方文档列出了如下错误场景,结合源码(internal/errors/errors.go)可确认其错误码来源:

错误场景错误消息触发条件
类型错误(Wrong type of value or key)(error) WRONGTYPE Operation against a key holding the wrong kind of value键中存储的不是 JSON 类型值。源码中通过object.AssertType(obj.Type, object.ObjTypeJSON)校验,失败时返回ErrWrongTypeOperation(internal/errors/errors.go)。
键不存在(Invalid Key)(error) ERR key does not exist对不存在的键执行追加。
路径不存在(Invalid Path)(error) ERR path %s does not existJSON 文档中不存在path指定的位置,对应ErrJSONPathNotFound(internal/errors/errors.go)。
路径处不是数组(Non Array Value at Path)(error) ERR path is not an arraypath指向的值不是数组。
非法的 JSON 值(Invalid JSON)(error) ERR invalid JSON传入的json_value不是合法的 JSON 字面量。

此外还有一类未在文档中单独列出、但由Arity: -3决定的错误:当参数个数少于 3 个(即缺少 value)时,返回ErrWrongArgumentCount("JSON.ARRAPPEND")错误(internal/errors/errors.go)。

示例用法

以下示例均基于 DiceDB 默认端口 7379 的命令行客户端(与官方文档一致)。

向数组追加单个值

127.0.0.1:7379> JSON.SET myjson . '{"numbers": [1, 2, 3]}' OK 127.0.0.1:7379> JSON.ARRAPPEND myjson .numbers 4 (integer) 4 127.0.0.1:7379> JSON.GET myjson "{\"numbers\":[1,2,3,4]}"

向数组追加多个值

127.0.0.1:7379> JSON.SET myjson . '{"fruits": ["apple", "banana"]}' OK 127.0.0.1:7379> JSON.ARRAPPEND myjson .fruits "cherry" "date" (integer) 4 127.0.0.1:7379> JSON.GET myjson "{\"fruits\":[\"apple\",\"banana\",\"cherry\",\"date\"]}"

键不存在时报错

127.0.0.1:7379> JSON.ARRAPPEND nonexistingkey .array 1 (error) ERR key does not exist

路径不存在时报错

127.0.0.1:7379> JSON.SET myjson . '{"numbers": [1, 2, 3]}' OK 127.0.0.1:7379> JSON.ARRAPPEND myjson .nonexistingpath 4 (error) ERR path .nonexistingpath does not exist

路径不是数组时报错

127.0.0.1:7379> JSON.SET myjson . '{"object": {"key": "value"}}' OK 127.0.0.1:7379> JSON.ARRAPPEND myjson .object 4 (error) ERR path is not an array

传入非法 JSON 时报错

127.0.0.1:7379> JSON.SET myjson . '{"numbers": [1, 2, 3]}' OK 127.0.0.1:7379> JSON.ARRAPPEND myjson .numbers invalidjson (error) ERR invalid JSON

进阶:在根路径处追加(根文档本身就是数组)

DiceDB 的 JSON 文档允许根节点即为数组,此时可用$作为路径直接在根数组上追加(该用法已被单元测试覆盖,见 internal/eval/eval_test.go):

127.0.0.1:7379> JSON.SET arr $ '[1,2,3]' OK 127.0.0.1:7379> JSON.ARRAPPEND arr $ 6 (integer) 4

进阶:递归路径一次追加多个数组

使用$..score这类递归 JSONPath 时,命令会命中所有匹配的数组并分别追加,返回各数组的新长度:

127.0.0.1:7379> JSON.SET doc $ '{"partner":{"name":"tom","score":[10]},"partner2":{"score":[10,20]}}' OK 127.0.0.1:7379> JSON.ARRAPPEND doc $..score 10 1) (integer) 2 2) (integer) 3

进阶:追加对象与数组等复合值

json_value支持任意合法 JSON,包括对象和数组字面量:

127.0.0.1:7379> JSON.SET doc $ '{"a":[{"b":1}]}' OK 127.0.0.1:7379> JSON.ARRAPPEND doc $.a '{"c":3}' (integer) 2 127.0.0.1:7379> JSON.SET arr $ '{"a":[[1,2]]}' OK 127.0.0.1:7379> JSON.ARRAPPEND arr $.a '[1,2,3]' (integer) 2

源码级实现剖析

JSON.ARRAPPEND的完整执行逻辑位于 internal/eval/store_eval.go 的evalJSONARRAPPEND函数,其处理流程可拆解为以下五个阶段:

  1. 参数校验:要求len(args) >= 3,即 key、path、至少一个 value,否则返回ErrWrongArgumentCount

  2. 取键与类型校验:通过store.Get(key)获取对象;对象不存在(或已过期)时返回NIL结果。随后调用object.AssertType(obj.Type, object.ObjTypeJSON)校验对象确为 JSON 类型,否则返回WRONGTYPE错误。

  3. JSONPath 解析:调用jp.ParseString(path)将路径字符串解析为 JSONPath 表达式,解析失败返回ErrJSONPathNotFound(path)

  4. 值解析:对每个json_value调用sonic.UnmarshalString(v, &parsedValue)解析为 JSON 值,任何解析失败都会以通用错误形式返回——这就是"非法 JSON"错误的来源。

  5. 就地修改:核心通过expr.Modify(jsonData, callback)完成:回调函数检查当前节点是否为[]interface{}数组,是则执行arr = append(arr, parsedValues...)并记录新长度到resultsArray;不是数组则在该位置记入NILModify返回后,若全程没有任何数组被修改(即路径完全不存在或没有匹配到数组),函数返回ErrJSONPathNotFound(path);否则将修改后的数据写回obj.Value并返回resultsArray

这一实现揭示了一个值得注意的细节:当前源码中,当 key 不存在或已过期时,命令返回的是(nil)Result: NIL, Error: nil),而不是文档中描述的ERR key does not exist错误。同时,递归路径下"部分匹配成功、部分不是数组"的场景会得到[长度, (nil), ...]的混合结果,而不是整体报错。这与 tests0/json_test.go 中的TestJsonARRAPPEND用例(如"JSON.ARRAPPEND nested with nil"期望返回[int64(2), "(nil)"])完全吻合,实际使用时请以线上实例的返回行为为准。

测试验证

DiceDB 为该命令提供了两层测试覆盖:

  • 单元测试:internal/eval/eval_test.go 直接构造evalJSONARRAPPEND的输入输出,覆盖追加嵌套数组值($.a追加[1,2,3])、追加对象值({"c":3})、递归多字段追加($..a返回[2,3])、根节点追加($)以及向数组追加不同类型值等场景,并断言 RESP 编码输出(如*2\r\n:2\r\n:3\r\n)。
  • 端到端测试:tests0/json_test.go 通过真实客户端连接执行命令序列,覆盖根路径追加、递归追加($..score)、递归命中非数组节点(返回nil)以及混合数据类型等用例。

这些测试不仅验证了命令的正确性,也为我们理解返回值的各种形态(单个整数、整数数组、含nil的混合数组)提供了最直接的依据。

注意事项与最佳实践

  • 确保 DiceDBJSON 模块已加载:使用JSON.ARRAPPEND前,需要确认实例已启用 DiceDBJSON 模块提供的 JSON 能力。
  • 熟悉 JSONPath 语法path使用 JSONPath 表达式定位文档位置。掌握.child$.root$..recursive等基础语法,可以更精准地控制追加目标;递归表达式会一次命中多个数组并返回多值结果。
  • 值为 JSON 字面量:追加字符串必须加引号("cherry"),追加数字、布尔值、null、对象、数组时按 JSON 语法书写,否则会触发"invalid JSON"错误。
  • 关注返回语义:单路径场景返回追加后数组的新长度,可直接用于判断操作是否生效;递归路径场景返回长度数组,其中nil表示对应节点不是数组。
  • 结合其他 JSON 命令使用JSON.ARRAPPEND通常与JSON.SET(初始化文档)、JSON.GET(查看结果)、JSON.ARRLEN(查询长度)、JSON.ARRPOP/JSON.ARRTRIM(数组收缩)配合,构成完整的数组生命周期管理。

通过本文档,读者可以全面掌握JSON.ARRAPPEND的语法、语义与实现细节,进而在 DiceDB 中自如地维护 JSON 数组数据。

【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 18:31:35

北京学会网站建设完整流程拆解:告别模板丑站,30天上线实录

北京学会网站建设完整流程拆解:告别模板丑站,30天上线实录 还在为找到的模板网站太丑、功能不够用而头疼吗?很多机构负责人拿到模板后,改改颜色就算完事,结果上线后客户觉得不专业,自己看着也难受。 这种“套壳”思维在学术和机构类网站建设中是死穴。今天咱们不谈虚的,直接复盘一个真实的 北京学会网站建设…

作者头像 李华
网站建设 2026/9/15 18:31:19

Flink实时风控系统落地复盘:特征计算、规则热更新与排障实践

把Flink接进风控系统之后&#xff0c;我最大的一个感悟是&#xff1a;实时风控这个事的难点&#xff0c;从来不在Flink本身。框架的API、窗口、状态管理&#xff0c;熟读文档总能学会&#xff1b;真正让团队掉进坑里的&#xff0c;是那些藏在"实时"二字背后的数据对齐…

作者头像 李华
网站建设 2026/9/15 18:30:31

HTML打包EXE全攻略:制作免安装绿色版与踩坑指南

上周同事拿U盘过来找我&#xff0c;说之前那个HTML小工具在这台电脑上打开是白屏。我看了一下&#xff0c;原因很简单&#xff1a;他直接把HTML文件拷过去了&#xff0c;CSS引用的本地路径全断了。这让我又一次动了把HTML一键打包成EXE的念头——做一个双击就能用的工具&#x…

作者头像 李华
网站建设 2026/9/15 18:30:14

OpenClaw模型量化:对称与非对称量化技术解析

1. OpenClaw模型量化中的量化方式解析OpenClaw作为当前热门的模型优化框架&#xff0c;其量化功能一直是开发者关注的焦点。在实际部署中&#xff0c;量化技术能显著减小模型体积、提升推理速度&#xff0c;而对称量化和非对称量化则是两种最基础的量化策略。1.1 对称量化的技术…

作者头像 李华
网站建设 2026/9/15 18:30:10

银行核心系统大文件分片上传与防篡改方案

1. 银行核心系统文件上传的安全挑战在银行核心业务系统中&#xff0c;交易记录上传功能的安全性和可靠性直接关系到金融数据的完整性。传统单文件上传方式在面对大体积交易记录文件时&#xff0c;主要面临三个核心问题&#xff1a;网络传输稳定性&#xff1a;当文件体积超过50M…

作者头像 李华
网站建设 2026/9/15 18:28:35

贝叶斯网络入门:从画图到条件独立,让概率推理有图可依

从公式堆里硬啃贝叶斯网络&#xff0c;是我见过最劝退的学习方式。这个领域的核心根本不是那串乘法公式&#xff0c;而是那张图。图才是贝叶斯网络真正“看得见、摸得着”的部分&#xff0c;节点代表随机变量&#xff0c;箭头代表影响关系&#xff0c;每个节点的条件概率表说明…

作者头像 李华