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

使用多个 JSON path 删除嵌套对象成员并保持剩余文档结构

来源:17golang原创

时间:2026-11-05 11:57:57 312浏览 收藏

如果只想从 MySQL 的 JSON 列里删除多个嵌套对象成员,直接把多个 JSON path 依次传给 JSON_REMOVE() 即可。关键是每个 path 都定位到要删除的叶子成员,并注意参数按从左到右处理:前一个 path 修改后的文档,会成为后一个 path 的输入。这样既能清理指定字段,也能保留父对象和其它同级字段。

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

推荐采用“先 SELECT 预览结果,再用主键限定 UPDATE”的生产写法。不要传根路径 $,也不要把父对象当成叶子成员删除;不存在的成员不会报错,但会让这条 path 对文档没有影响。

一、先把生产目标收窄到叶子成员

假设表中有一个 profile_json JSON 列,文档结构如下:

-- 这份样例同时保留联系信息、偏好设置和不应被删除的字段
SET @profile = '{
  "profile": {"display_name": "Lin", "phone": "13800000000", "region": "华东"},
  "preferences": {"debug": true, "theme": "dark"},
  "member_level": "pro"
}';

本次需求是删除 profile.phone 和 preferences.debug,而 profile.display_name、profile.region、preferences.theme 以及根部的 member_level 都要保留。因此目标 path 是 $.profile.phone 与 $.preferences.debug,而不是 $.profile 或 $。

JSON 文档中 profile 和 preferences 两个嵌套对象及其待删除叶子成员的结构说明图
图1:结构说明图,查看两个嵌套对象、待删除叶子成员和需要保留的同级字段之间的边界。

二、准备路径清单并先预览结果

JSON_REMOVE(json_doc, path[, path] ...) 返回修改后的 JSON 文档。传入的文档必须是有效 JSON;任意参数为 SQL NULL 时结果为 NULL;path 不能是根路径 $,也不能含 * 或 ** 通配符。对象成员不存在时不是错误,这个 path 会被忽略。

-- 先只计算新文档,不改变表数据,便于人工确认删除边界
SELECT JSON_REMOVE(
  @profile,
  '$.profile.phone',
  '$.preferences.debug'
) AS preview_json;

预览结果应当只移除两个成员,父对象仍然存在:

{"profile": {"display_name": "Lin", "region": "华东"}, "preferences": {"theme": "dark"}, "member_level": "pro"}

这一步还可以发现路径拼写问题。例如把 $.preferences.debug 写成不存在的 $.preference.debug,函数不会把它当成语法错误,也不会删除其它字段,所以生产脚本应把路径清单作为变更记录的一部分。

三、多个 path 为什么必须考虑从左到右

MySQL 会按参数出现的顺序处理 path。每次修改生成的新文档,会继续作为下一个 path 的输入。删除两个互不相干的叶子成员时,顺序通常不会改变结果;但如果先删除父对象,后面的嵌套 path 就失去匹配对象。

-- 正确:两个 path 都指向独立的叶子成员,剩余结构仍然完整
SELECT JSON_REMOVE(
  @profile,
  '$.profile.phone',
  '$.preferences.debug'
) AS cleaned_json;

-- 有风险:先删掉 profile,后面的 profile.phone 已经没有匹配对象
SELECT JSON_REMOVE(
  @profile,
  '$.profile',
  '$.profile.phone'
) AS parent_first_json;

第二种写法不会报错,但它表达的是“删除整个 profile”,不是“删除 profile 里的一个成员”。如果业务要求保留父对象,路径清单应只允许叶子成员;如果确实要删除整个对象,也应在发布单中明确写出这个更大的影响范围。

JSON_REMOVE 多个路径从左到右作用于已修改文档的关系说明图
图2:关系说明图,查看多个 JSON path、已修改文档和父对象先删除后续路径失配的静态关系。

四、生产 UPDATE 的权限、审计与发布检查

确认预览结果后,再把同一个表达式放进限定主键的 UPDATE。对于批量清理,不要省略 WHERE,也不要把“路径不存在不会报错”误当成“所有行都已经完成清理”。

-- 只更新指定记录,并跳过 SQL NULL,避免把文档结果写成 NULL
START TRANSACTION;

UPDATE customer_profile
SET profile_json = JSON_REMOVE(
  profile_json,
  '$.profile.phone',
  '$.preferences.debug'
)
WHERE id = 1001
  AND profile_json IS NOT NULL;

-- 发布前读取同一条记录,确认目标字段已移除、其它字段仍在
SELECT id, profile_json
FROM customer_profile
WHERE id = 1001;

-- 应用层审计完成后再提交;发现范围不对就回滚
COMMIT;

权限上只给执行该表更新所需的最小权限,并把主键范围、path 清单、预览结果和影响行数写入变更记录。若需要清理多行,可以先按主键分批生成预览,再在同一事务策略下执行;不要用一个没有过滤条件的更新语句测试路径。

这里的 profile_json IS NOT NULL 只是在 SQL 层排除空列。JSON 文档里的 JSON null 与 SQL NULL 不是同一概念,处理前应按业务字段约定区分。

相关问题

删除路径不存在时会失败吗?

不会。只要 JSON 文档和 path 本身合法,目标成员不存在时该 path 对文档没有影响;因此仍应通过预览和审计记录确认实际清理范围。

为什么不直接删除整个嵌套对象?

删除父对象会连同其中所有成员一起消失。需要保持剩余文档结构时,应使用指向具体对象成员的 path,并把父对象先删除的写法视为不同的变更。

小结:多成员清理的核心不是把 path 写得越多越好,而是让每个 path 都有明确边界;先预览、再按从左到右规则检查,最后用主键和事务策略发布。

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