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

MySQL JSON_ARRAY_APPEND 怎样把值追加到嵌套数组

来源:17golang原创

时间:2026-11-15 10:56:01 248浏览 收藏

如果一列 JSON 里还有订单、事件或标签等嵌套数组,想在末尾加入一个新值,MySQL 的 JSON_ARRAY_APPEND() 比先取出整段 JSON、在应用层改完再写回更直接。它按 JSON 路径定位数组并追加值;路径命中标量时会自动包装成数组,路径没有匹配对象时则忽略这一对参数。

官方地址:https://dev.mysql.com/doc/refman/8.4/en/json-modification-functions.html

最稳妥的记法是:JSON_ARRAY_APPEND(json_doc, path, value) 只负责“在命中的位置末尾追加”,不负责“插到第几个位置”。嵌套数组用完整路径定位;如果需要指定下标,应改看 JSON_ARRAY_INSERT()。

JSON_ARRAY_APPEND 追加的到底是什么

函数的基本形态是 JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)。第一个参数是合法 JSON 文档,之后每两个参数组成一对路径和值。路径指向数组时,新值进入数组末尾;如果指向的是对象或数字、字符串这样的标量,MySQL 会先把它自动包装成数组再追加。

MySQL JSON_ARRAY_APPEND 从 JSON 文档经路径定位到嵌套数组并追加 JSON 值的结构说明图
图1:JSON 文档、路径、目标数组和追加值之间的静态关系;这是原创结构说明图,不是 SQL 运行截图。

例如订单文档中有一个 items 数组,可以把新的商品对象作为 JSON 值传入:

-- 给第一个订单的 items 数组追加一个商品对象
SELECT JSON_ARRAY_APPEND(
    '{"orders":[{"items":[{"sku":"A1"}]}]}',
    '$.orders[0].items',
    JSON_OBJECT('sku', 'B2', 'qty', 1)
) AS updated_doc;

这里的路径先进入 orders 数组的第一个元素,再进入它的 items 成员。JSON_OBJECT() 返回的是 JSON 对象,所以追加结果中的新元素是对象,而不是带引号的普通字符串。

嵌套数组路径怎样写才不会追加错层级

嵌套数据最容易出错的地方,是把“订单数组”“订单对象”和“订单对象里的 items 数组”混成同一层。先把文档的层级写出来,再把每个数组下标和对象键连起来,路径就比较清楚:

-- 目标是 orders[0] 对象里的 items 数组,不是整个 orders 数组
SET @doc = '{"orders":[{"id":101,"items":["book"]}]}';

-- 在嵌套 items 数组末尾追加一个字符串值
SELECT JSON_ARRAY_APPEND(@doc, '$.orders[0].items', 'pen') AS updated_doc;

-- 让追加值保持对象形态,避免把对象文本当成普通字符串
SELECT JSON_ARRAY_APPEND(
    @doc,
    '$.orders[0].items',
    JSON_OBJECT('sku', 'P01', 'qty', 2)
) AS updated_doc;

如果路径命中了标量,结果不会报“目标不是数组”,而是发生自动包装:

-- c 原来是数字,命中后会先变成 [4],再追加 9
SELECT JSON_ARRAY_APPEND(
    '{"a":[2,3],"c":4}',
    '$.c',
    9
) AS updated_doc;

-- 不存在的 missing 路径不会自动创建成员,结果保持不变
SELECT JSON_ARRAY_APPEND(
    '{"a":[2,3]}',
    '$.missing.items',
    'x'
) AS unchanged_doc;

这两个边界决定了排障方向:看到数组结构突然多了一层,先查路径是否实际指向了标量;看到结果没有变化,先查对象键是否存在以及路径表达式是否有效。

一次追加多个值时要按左到右阅读

同一次调用可以传多组 path, value。MySQL 会从左到右求值,前一对参数产生的文档会成为后一对参数的输入,因此不要把所有路径都当成针对原始文档独立执行。

MySQL JSON_ARRAY_APPEND 多路径左到右求值与标量自动包装和未命中边界关系图
图2:多路径参数、左到右求值、标量包装和未命中路径的边界关系;这是原创静态说明图,不是运行证据。
-- 两对路径按左到右处理,第二对基于第一对产生的文档继续追加
SELECT JSON_ARRAY_APPEND(
    '{"tags":["mysql"],"meta":{"labels":["sql"]}}',
    '$.tags', 'json',
    '$.meta.labels', 'database'
) AS updated_doc;

如果多组参数里任意参数是 SQL NULL,函数会返回 NULL;非法 JSON 文档、非法路径或包含 *、** 通配符的路径会报错。JSON 文档里的字符串值则应使用合法 JSON 文本或 JSON 构造函数,避免把本来想追加的对象写成带引号的字符串。

放进 UPDATE 时怎样保留原文档结构

真正更新 JSON 列时,把原列作为第一个参数,并用明确的 WHERE 限定记录。下面的写法只修改目标行的 events 数组:

-- 只给指定订单追加一次发货事件,避免无条件更新整张表
UPDATE order_log
SET payload = JSON_ARRAY_APPEND(
    payload,
    '$.events',
    JSON_OBJECT(
        'type', 'shipped',
        'carrier', 'standard'
    )
)
WHERE order_id = 101;

-- 读取更新后的数组,确认查询路径和写入路径保持一致
SELECT JSON_EXTRACT(payload, '$.events') AS events
FROM order_log
WHERE order_id = 101;

需要指定插入位置时,不能靠调整 JSON_ARRAY_APPEND() 的路径来实现。JSON_ARRAY_INSERT() 才是按数组下标插入的函数;两者都按多路径从左到右处理,但插入会改变后续数组位置,追加则只关心末尾。

需求函数注意点
事件、标签追加到数组末尾JSON_ARRAY_APPEND()目标为标量时会自动包装
插入到指定下标前JSON_ARRAY_INSERT()后续下标可能因前一次插入而变化
只在路径不存在时写入JSON_INSERT()已有路径不会覆盖
覆盖已有成员或元素JSON_SET()应单独确认是否需要部分更新语义

常见问题

为什么追加对象后变成了字符串? 如果把对象 JSON 直接作为普通 SQL 字符串传入,结果可能保留字符串形态。用 JSON_OBJECT() 或明确的 JSON 值构造方式传参,更容易保持对象结构。

路径不存在时能否自动创建数组? JSON_ARRAY_APPEND() 不会因为路径未命中就创建缺失成员。需要初始化结构时,应先用合适的 JSON 写入函数建立路径,再执行追加。

怎样向数组开头添加值? 这不是追加语义,应使用 JSON_ARRAY_INSERT() 指定 $[0] 等位置,并重新检查后续路径的下标变化。

记住“路径命中谁、值是什么类型、参数按什么顺序求值”这三个问题,就能稳定处理 MySQL JSON 中的嵌套数组追加。

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