Go JSONPatch 怎样合并两份 JSON Merge Patch
来源:17golang原创
时间:2026-10-29 12:36:27 208浏览 收藏
两份 JSON Merge Patch 不必先手动解码成 map[string]any 再拼接。Go 中可以直接调用 jsonpatch.MergeMergePatches(patchA, patchB) 得到一份组合补丁,再用 jsonpatch.MergePatch(document, combinedPatch) 应用到原文档。需要特别留意补丁顺序:同名字段由后一个补丁覆盖,null 表示删除对象字段,数组则按整体值替换。
官方地址:https://github.com/evanphx/json-patch
如果两份输入都是 JSON Merge Patch,优先使用 MergeMergePatches;它表达的是“先应用第一份,再应用第二份”的合并结果,不是 JSON Patch 数组操作的拼接。
项目目标:把两份局部配置合成一份
假设一个配置中心收到两份局部更新:团队补丁负责改姓名和身高,功能补丁负责改年龄、增加眼睛颜色。我们希望把它们组合成一份补丁,交给不同环境的原始文档重复使用。
依赖使用 v5 模块路径:
# 初始化一个最小 Go 项目,并引入 JSON Patch 库 go mod init example.com/mergepatch-demo go get github.com/evanphx/json-patch/v5
先把输入拆成两个对象形状的 Merge Patch。对象字段只代表需要变更的部分,因此不需要把完整配置复制两遍。
package main
import "fmt"
func main() {
// 团队补丁只负责身份和身高字段。
teamPatch := []byte(`{"name":"Jane","height":null}`)
// 功能补丁只负责年龄和新字段,后者不会影响前一个补丁的 name。
featurePatch := []byte(`{"age":28,"eyes":"blue"}`)
fmt.Printf("team=%s feature=%s\n", teamPatch, featurePatch)
}

核心代码:调用 MergeMergePatches
MergeMergePatches 接收两段 JSON 字节,并返回新的 JSON 字节。它不是把两个字符串直接拼接,而是按 Merge Patch 的对象语义递归处理字段;输入非法时要保留错误,不要把结果当成可用配置继续向下传。
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch/v5"
)
func composeAndApply(document, first, second []byte) ([]byte, error) {
// second 放在后面,冲突字段会采用第二份补丁的值。
combined, err := jsonpatch.MergeMergePatches(first, second)
if err != nil {
return nil, fmt.Errorf("合并 Merge Patch 失败: %w", err)
}
// 组合补丁可以复用于另一份结构相同的原始文档。
result, err := jsonpatch.MergePatch(document, combined)
if err != nil {
return nil, fmt.Errorf("应用组合补丁失败: %w", err)
}
return result, nil
}
func main() {
// 原文档保留未被补丁提到的字段,供局部更新使用。
document := []byte(`{"name":"John","age":24,"height":3.21}`)
first := []byte(`{"name":"Jane","height":null}`)
second := []byte(`{"age":28,"eyes":"blue"}`)
result, err := composeAndApply(document, first, second)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(result))
}
这个小项目的关键是把“组合”与“应用”分开:前者只产生新的补丁,后者才需要原始文档。这样同一份组合补丁可以用于测试配置、灰度配置和正式配置,而不必修改输入字节。
如何确认组合语义与依次应用一致
工程代码中可以把两种路径并排比较:路径一先应用第一份,再应用第二份;路径二只应用组合补丁。库提供的 Equal 比较 JSON 结构而不是字节顺序,适合处理对象键顺序不同但内容相同的情况。
// sequentialApply 表示按接收顺序逐份应用补丁。
func sequentialApply(document, first, second []byte) ([]byte, error) {
step, err := jsonpatch.MergePatch(document, first)
if err != nil {
return nil, err
}
return jsonpatch.MergePatch(step, second)
}
// comparePaths 用结构比较避免把 JSON 字符串顺序误判为结果不同。
func comparePaths(document, first, second []byte) error {
combined, err := jsonpatch.MergeMergePatches(first, second)
if err != nil {
return err
}
left, err := sequentialApply(document, first, second)
if err != nil {
return err
}
right, err := jsonpatch.MergePatch(document, combined)
if err != nil {
return err
}
if !jsonpatch.Equal(left, right) {
return fmt.Errorf("两条应用路径的 JSON 结构不一致")
}
return nil
}
对上面的输入,组合补丁的结构可以理解为:
{
"age": 28,
"eyes": "blue",
"height": null,
"name": "Jane"
}
这里的 JSON 只是预期的结构示意。真正的判断应交给代码中的结构比较,并在业务边界上保留错误处理。

四个容易误用的边界
| 输入情况 | 合并时的理解 | 工程提醒 |
|---|---|---|
| 同名普通字段 | 后一个补丁的值覆盖前一个补丁 | 定义清楚补丁顺序,必要时记录来源 |
字段值为 null | 对象字段表示删除 | 不能把 null 当作“保留空值”的通用表达 |
| 同名嵌套对象 | 对象成员继续按 Merge Patch 语义合并 | 删除嵌套成员要在对应层级写 null |
| 数组字段 | 数组通常作为整体值替换 | 不能用它表达数组中某个元素的精细增删 |
因此,Merge Patch 适合对象型配置的局部更新;如果需求是移动数组元素、按索引删除或表达一串明确操作,应评估 JSON Patch 的操作数组,而不是继续堆叠 Merge Patch。
常见问题
两份补丁有同一个字段时谁生效?
以传入顺序为准,第二份补丁覆盖第一份补丁的同名结果。调用方应固定排序规则,不要依赖 map 的遍历顺序。
为什么合并数组后不是只增加一个元素?
JSON Merge Patch 把数组看作字段值,通常会整体替换。要操作数组内部位置,应改用 JSON Patch 或在业务层定义专门的追加、删除命令。
-
860 收藏
-
843 收藏
-
826 收藏
-
809 收藏
-
792 收藏
-
302 收藏
-
334 收藏
-
135 收藏
-
232 收藏
-
355 收藏
-
360 收藏
-
446 收藏
-
210 收藏
-
200 收藏
-
187 收藏
-
164 收藏
-
139 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习