为一个巨大的对象撤消重做
Undo redo for a huge object
我有一个要求,产品需要实现撤销-重做功能。
目前我持有一个来自单个 mongo 集合的巨大对象。
伪结构:
{
cart:{
products:[
{
name: "Watch",
quantity: 1,
shippingDate: 123456782,
text: "lorem ipsum....",
prices:[
{
currency: "USD",
price: 300
},
{
currency: "GBP",
price: 220
}
]
}
],
...someMoreKeyValuePair
}
}
现在可以在任何节点上进行更新,例如:产品获取 added/modified/removed、购物车级别数据获取 added/modified/removed。
并且结构非常庞大,现在我如何维护对整个结构发生的任何更改的撤消-重做操作。
我应该阅读哪些数据结构或设计模式以获得更好的解决方法。
更新:
undo-redo 需要保存在数据库中。我使用的语言是 Javascript-NodeJS
您可以使用 deep-diff,例如。
deep-diff is a javascript/node.js module providing utility functions
for determining the structural differences between objects and
includes some utilities for applying differences across objects.
因此您可以在版本之间创建差异,并将它们存储在您的数据库中:
const change = diff(oldValue, newValue);
要应用差异:
applyChange(target, source, change);
jsondiffpatch is another option. If you use Mongoose, you can implement a plugin for managing changes, or use an existing one: mongoose-diff-history
您需要保留更改日志。因此,您的服务器应用程序 (nodejs) 处理的客户端请求应转换为 both 的数据库操作
记录更改(像撤销日志一样)并在一个事务中执行它。
然后实施逻辑以在适当的时候清除撤消日志,从该日志中弹出一个操作并执行反向操作,...等等
这样的撤消日志中的一条记录将包含 3 到 4 个元素:
- 一个动作:“更新”、“插入”或“删除”。后两者主要用于表示数组操作。
- 用于标识应在对象中应用更改的位置的路径。该路径将是一个属性数组,例如可以将其编码为以点分隔的字符串。
- 该位置的旧值(在“更新”或“删除”的情况下),JSON 编码。
- 该位置的新值(在“更新”或“插入”的情况下),JSON 编码。
此类记录的示例:
("update", "cart.products.0.name", '"Watch"', '"Watching"')
("delete", "cart.products.prices.1", '{"currency":"GBP","price":220}', null)
:这表示从 prices
数组的索引 1 中删除旧值的操作。间隙通过移动数组值来填补,很像 JavaScript. 中的 splice(index, 1)
操作
("insert", "cart.products.prices.0", null, '{"currency":"EUR","price":270}')
:这表示将新值插入到 prices
数组中的索引 0 处的操作。如果该索引已经有一个值,它将向右移动,就像 JavaScript. 中的 splice(index, 0, newvalue)
操作一样
null
值仅表示此参数与该特定操作无关。
以上示例日志将累积到以下数据,从您提供的示例数据开始:
{
cart:{
products:[
{
name: "Watching",
quantity: 1,
shippingDate: 123456782,
text: "lorem ipsum....",
prices:[
{
currency: "EUR",
price: 270
},
{
currency: "USD",
price: 300
}
]
}
]
}
}
这样的日志包含撤消操作的所有内容:如果数据被擦除(“更新”、“删除”),您可以从第三个参数恢复被擦除的数据。
我有一个要求,产品需要实现撤销-重做功能。
目前我持有一个来自单个 mongo 集合的巨大对象。
伪结构:
{
cart:{
products:[
{
name: "Watch",
quantity: 1,
shippingDate: 123456782,
text: "lorem ipsum....",
prices:[
{
currency: "USD",
price: 300
},
{
currency: "GBP",
price: 220
}
]
}
],
...someMoreKeyValuePair
}
}
现在可以在任何节点上进行更新,例如:产品获取 added/modified/removed、购物车级别数据获取 added/modified/removed。
并且结构非常庞大,现在我如何维护对整个结构发生的任何更改的撤消-重做操作。
我应该阅读哪些数据结构或设计模式以获得更好的解决方法。
更新:
undo-redo 需要保存在数据库中。我使用的语言是 Javascript-NodeJS
您可以使用 deep-diff,例如。
deep-diff is a javascript/node.js module providing utility functions for determining the structural differences between objects and includes some utilities for applying differences across objects.
因此您可以在版本之间创建差异,并将它们存储在您的数据库中:
const change = diff(oldValue, newValue);
要应用差异:
applyChange(target, source, change);
jsondiffpatch is another option. If you use Mongoose, you can implement a plugin for managing changes, or use an existing one: mongoose-diff-history
您需要保留更改日志。因此,您的服务器应用程序 (nodejs) 处理的客户端请求应转换为 both 的数据库操作 记录更改(像撤销日志一样)并在一个事务中执行它。
然后实施逻辑以在适当的时候清除撤消日志,从该日志中弹出一个操作并执行反向操作,...等等
这样的撤消日志中的一条记录将包含 3 到 4 个元素:
- 一个动作:“更新”、“插入”或“删除”。后两者主要用于表示数组操作。
- 用于标识应在对象中应用更改的位置的路径。该路径将是一个属性数组,例如可以将其编码为以点分隔的字符串。
- 该位置的旧值(在“更新”或“删除”的情况下),JSON 编码。
- 该位置的新值(在“更新”或“插入”的情况下),JSON 编码。
此类记录的示例:
("update", "cart.products.0.name", '"Watch"', '"Watching"')
("delete", "cart.products.prices.1", '{"currency":"GBP","price":220}', null)
:这表示从prices
数组的索引 1 中删除旧值的操作。间隙通过移动数组值来填补,很像 JavaScript. 中的 ("insert", "cart.products.prices.0", null, '{"currency":"EUR","price":270}')
:这表示将新值插入到prices
数组中的索引 0 处的操作。如果该索引已经有一个值,它将向右移动,就像 JavaScript. 中的
splice(index, 1)
操作
splice(index, 0, newvalue)
操作一样
null
值仅表示此参数与该特定操作无关。
以上示例日志将累积到以下数据,从您提供的示例数据开始:
{
cart:{
products:[
{
name: "Watching",
quantity: 1,
shippingDate: 123456782,
text: "lorem ipsum....",
prices:[
{
currency: "EUR",
price: 270
},
{
currency: "USD",
price: 300
}
]
}
]
}
}
这样的日志包含撤消操作的所有内容:如果数据被擦除(“更新”、“删除”),您可以从第三个参数恢复被擦除的数据。