【总结】2247- 更新大的 JSON 对象,也能用上增量更新!

科技   2024-11-14 21:55   福建  

什么是 JSON Patch

JSON Patch[1] 是一种用于描述如何对 JSON 文档进行更改的格式,它使用一系列简洁的操作指令来指示如何修改 JSON 数据。这些操作包括添加新的数据、删除旧的数据、替换现有的数据或者移动数据等等。

为什么使用 JSON Patch

在一个大型的 Web 应用程序中,客户端需要频繁地与服务器通信,获取最新的数据或者将修改后的数据提交给服务器。传统的方式是每次更新都发送整个 JSON 文档,即使只有一小部分数据发生了变化。这会导致网络传输量大,增加了网络延迟,同时也增加了服务器和客户端的负载。

JSON Patch 提供了一种高效的解决方案来减少网络传输量和提高数据更新效率。通过使用 JSON Patch,客户端可以仅发送需要修改的部分数据,而不是整个 JSON 文档。服务器收到 JSON Patch 后,可以根据指令执行相应的操作,从而实现数据的增量更新。这样既减少了网络传输量,提高了网络效率,又降低了服务器和客户端的负载,同时也保证了数据的一致性。

JSON Patch 有哪些优点

  • 减少传输量:JSON Patch 只传输要对 JSON 文档进行的具体更改,而不需要传输整个 JSON 文档。这样可以节省网络带宽,尤其在大型数据集或者低速网络环境下更为显著。

  • 增量更新:JSON Patch 支持对 JSON 文档进行增量更新,这意味着你可以只发送需要修改的部分,而不是整个文档。这对于实时应用程序以及需要频繁更新的情况非常有用。

  • 原子性操作:JSON Patch 操作可以作为一个原子单元执行,这意味着要么全部操作成功,要么全部失败。这可以确保数据的一致性,避免因为部分更新导致数据不一致的情况。

  • 灵活性和可扩展性:JSON Patch 不限制你对 JSON 文档进行的操作,你可以根据需求执行添加、删除、替换、移动等各种操作,并且可以根据实际需求扩展新的操作。

JSON Patch 支持哪些操作

1.add

向 JSON 文档中添加新的值,需要指定路径和要添加的值。

"op""add""path""/path""value""new value" }

2.remove

从 JSON 文档中移除一个值,需要指定要移除的值的路径。

"op""remove""path""/path" }

3.replace

替换 JSON 文档中的一个值,需要指定要替换的值的路径和新的值。

"op""replace""path""/path""value""new value" }

4.move

移动 JSON 文档中的一个值到另一个位置,需要指定要移动的值的路径和目标路径。

"op""move""from""/oldpath""path""/newpath" }

5.copy

复制 JSON 文档中的一个值到另一个位置,需要指定要复制的值的路径和目标路径。

"op""copy""from""/oldpath""path""/newpath" }

6.test

测试 JSON 文档中的一个值是否等于给定的值,主要用于验证操作是否可以成功执行。需要指定要测试的值的路径和预期的值。

"op""test""path""/path""value""expected value" }

如何使用 JSON Patch

很多常见的开发语言,都实现了 JSON Patch 规范。在 JS 环境,我们可以使用 fast-json-patch[2] 这个库。

首先,使用 npm 或 pnpm 来安装 fast-json-patch

npm install fast-json-patch
or 
pnpm add fast-json-patch

成功安装 fast-json-patch 库之后,我们就可以利用它提供的 API 来实现以下功能:

  1. 比较两个对象获取补丁
  2. 观察对象变化并在检测到变化时生成补丁
  3. 在 JS 对象上应用单个或多个补丁
  4. 验证补丁序列

1.比较两个对象获取补丁

import { compare } from "fast-json-patch/index.mjs";

const documentA = { user: { firstName"Albert"lastName"Einstein" } };
const documentB = { user: { firstName"Albert"lastName"Collins" } };

const diff = compare(documentA, documentB);
/**
 * diff: 
 * [ { op: 'replace', path: '/user/lastName', value: 'Collins' } ]
 */

2.观察对象变化并在检测到变化时生成补丁

import { generate, observe } from "fast-json-patch/index.mjs";

const document = {
  firstName"Joachim",
  lastName"Wester",
  contactDetails: { phoneNumbers: [{ number"555-123" }] },
};
const observer = observe(document);
document.firstName = "Albert";
document.contactDetails.phoneNumbers[0].number = "123";
document.contactDetails.phoneNumbers.push({ number"456" });
const patch = generate(observer);

/**
 * patch:
 * [
 *  {
 *    op: 'replace',
 *    path: '/contactDetails/phoneNumbers/0/number',
 *    value: '123'
 *  },
 *  {
 *   op: 'add',
 *   path: '/contactDetails/phoneNumbers/1',
 *   value: { number: '456' }
 *  },
 *  { op: 'replace', path: '/firstName', value: 'Albert' }
 * ]
 */

3.在 JS 对象上应用单个或多个补丁

应用单个补丁

import { applyPatch } from "fast-json-patch/index.mjs";

const documentA = { user: { firstName"Albert"lastName"Einstein" } };
const patchedResult = applyPatch(documentA, [
  { op"replace"path"/user/lastName"value"Collins" },
]);

/**
 * patchedResult[0]:
 * {
 *   newDocument: { user: { firstName: 'Albert', lastName: 'Collins' } },
 *   removed: 'Einstein'
 * }
 */

应用多个补丁

import { applyPatch } from "fast-json-patch/index.mjs";

const document = {
  firstName"Joachim",
  lastName"Wester",
  contactDetails: { phoneNumbers: [{ number"555-123" }] },
};

const patchedResult = applyPatch(document, [
  {
    op"replace",
    path"/contactDetails/phoneNumbers/0/number",
    value"123",
  },
  {
    op"add",
    path"/contactDetails/phoneNumbers/1",
    value: { number"456" },
  },
  { op"replace"path"/firstName"value"Albert" },
]);

/**
 * patchedResult[0]: 
 * {
 *  newDocument: {
 *    firstName: "Albert",
 *    lastName: "Wester",
 *    contactDetails: { phoneNumbers: [{ number: "123" }, { number: "456" }] },
 *  },
 *  removed: "555-123",
 * }
 */

4.验证补丁序列

import { validate } from "fast-json-patch/index.mjs";

const documentA = { user: { firstName"Albert"lastName"Einstein" } };
const validatedResult = validate(
  [{ op"replace"path"/user/lastName"value"Collins" }],
  documentA
);

如果补丁序列不满足 JSON Patch 规范,在验证过程中就会抛出 JsonPatchError 异常对象。

JSON Patch 和 fast-json-patch 的相关内容就介绍到这里,感兴趣的话,可以尝试一下 JSON Patch。如果你有其他方案,可以给我留言。

参考资料
[1]

JSON Patch: https://datatracker.ietf.org/doc/html/rfc6902

[2]

fast-json-patch: https://github.com/Starcounter-Jack/JSON-Patch

前端自习课
每日清晨,享受一篇前端优秀文章。
 最新文章