JSON对象的Delta编码

时间:2011-09-06 21:46:07

标签: javascript json node.js

是否有标准库或工具用于计算和应用差异到JSON文档?基本上我有一堆大文件,我希望通过网络保持同步,我宁愿避免每次我想要同步它们时重新发送它们的整个状态(因为这些变量很多都不会改变)。换句话说,我只想传输更改的字段,而不是重新传输整个对象。我认为使用以下一组方法会很方便:

//Start with two distinct objects on the server
// prev represents a copy of the state of the object on the client
// next represents a copy of the state of the object on the server
//
//1. Compute a patch
patch = computePatch(prev, next);

//2. Send patch over the network

//3. Apply the patch on the client
applyPatch(prev, patch);

//Final invariant:
//   prev represents an equivalent object to JSON.parse(JSON.stringify(next))

我当然可以自己实现一个,但是有很多边缘情况需要考虑。以下是我能想到的一些简单(虽然有些不令人满意)的方法,例如:

  1. 滚动我自己的JSON修补程序。渐近地,这可能是最好的方法,因为它可以支持JSON文档的所有相关功能,并支持一些专门的方法来执行诸如diffing int,double和string之类的东西(使用相对编码/编辑距离) 。然而,JSON有很多特殊情况,我有点怀疑没有经过大量测试就试图这样做,所以我更愿意找到一些已经解决了这个问题的东西让我相信它,并且不必担心由于我的JSON补丁中的错误而出现的网络Heisenbugs

  2. 使用动态编程直接计算JSON字符串之间的编辑距离。不幸的是,如果客户端和服务器具有不同的JSON实现(即,它们的字段的顺序可以不同地序列化),则这不起作用,并且作为二次时间操作也是相当昂贵的。

  3. 使用协议缓冲区。协议缓冲区有一个内置的diff方法,它正是我想要的,它们是一个很好的二进制可序列化的网络友好格式。不幸的是,因为它们也是严格类型的,它们缺少使用JSON的许多优点,例如动态添加和删除字段的能力。现在这是我目前所倾向的方法,但它可能会使未来的维护变得非常糟糕,因为我需要不断更新我的每个对象。

  4. 做一些非常讨厌的事情,比如为每种类型的对象制作一个自定义协议,并希望我能在两个地方做到正确(是的!)。

  5. 当然,我真正希望的是这里的stackoverflow上的某个人通过参考一个节省空间的javascript对象的区别来保存这一天不同/修补程序已在生产环境和多个浏览器中经过良好测试。< / p>

    *的 更新 *

    我开始编写自己的修补程序,它的早期版本可以在github上找到:

    https://github.com/mikolalysenko/patcher.js

    我想因为这里似乎没有多少,我会接受一个JSON修补程序的有趣测试用例列表作为替代答案。

5 个答案:

答案 0 :(得分:12)

我一直在和json diff&amp; amp; github上的补丁库(是的,无耻的插件):

https://github.com/benjamine/JsonDiffPatch

它使用Neil Fraser的diff_match_patch lib自动处理长字符串。 它适用于浏览器和服务器(在两个env上运行的单元测试)。 (完整功能列表在项目页面上)

你唯一可能需要的,没有实现的是为特定对象注入自定义diff / patch函数的选项,但这听起来并不难添加,欢迎你来分叉,甚至更好的发送拉请求。

此致

答案 1 :(得分:5)

我遇到了这个问题,寻找json-patch的实现。如果你自己动手,你可能希望以此草案为基础。

http://tools.ietf.org/html/draft-pbryan-json-patch-00

答案 2 :(得分:4)

JSON-patch标准已更新。

http://tools.ietf.org/html/draft-ietf-appsawg-json-patch-10

您可以在https://github.com/Starcounter-Jack/Fast-JSON-Patch

找到应用修补程序和生成修补程序的实现

答案 3 :(得分:1)

在你开始编写自己的JSON差异和扩展之前从头开始修补实用程序,我建议利用现有的差异和扩展用于纯文本的补丁实用程序您真正需要做的就是编写一些逻辑,该逻辑采用任意JSON字符串并以“规范”JSON格式呈现 - 这样任何两个代表等效数据的JSON字符串都具有与文本字符串相同的“规范”形式 - 然后您可以使用普通的旧“补丁”为你计算所有的增量。

似乎canonical JSON的想法并不新鲜,但为任意JSON字符串生成规范表示所需的代码并不简单,看起来谷歌叔叔的所有内容都有改进的余地。现在向我展示“规范JSON”(包括this question的答案,尽管使用Bencode作为规范化格式听起来很有希望。)

这是个好消息,因为这意味着你可以写一些新的有用的东西!当你找到一个可行的解决方案时让我们发布(我也希望能够生成JSON增量)。

编辑:在考虑了这一点后,我意识到“规范化”的想法根本没有帮助,因为相同的delta / patch 通常不能应用两个文本上不同的JSON块,即使它们具有相同的“规范形式”。这就引出了一个问题 - 如果您只是通过线路为JSON文档发送“deltas”,那么为什么不简单地将它们作为文字明文差异(或者类型为text / x-diff的MIME文档)发送?为防止因修补程序丢失而导致的损坏,您可能需要在某处添加序列/版本号字段(包括数据文件和差异),或者您可以野心勃勃并使用the Delta-V protocol(为WebDAV开发)。也许你已经这样做了?我将在本周晚些时候尝试查看您的代码。

答案 4 :(得分:1)

使用JSON Patch the standard way to do this。{/ p>

许多平台都存在库

在撰写本文时,支持Javascript,Python,PHP,Ruby,Perl,C,Java,C#,Go,Haskell和Erlang(full list here)。

  

JSON Patch是一种用于描述对a的更改的格式   JSON文档。它可用于避免在何时发送整个文档   只有一部分发生了变化。与HTTP PATCH结合使用时   它允许在标准中对HTTP API进行部分更新   合规的方式。

     

补丁文档本身就是JSON文档。

     

JSON Patch在IETF的RFC 6902中指定。