在本演示教程中,我们将展示如何应用差异和修补操作来监控TerminuDB模式、TerminuSB文档、JSON模式和其他文档数据库(如MongoDB)中的更改。
关于JSON、差异和补丁的一点背景知识
Git分布式管理源代码策略中的一个基本工具是diff和补丁的概念。这些基本操作使git成为可能。Diff用于构造可应用于对象的面片,以使最终状态对某些值有意义。
但是结构化数据呢?对于需要差异和修补操作的结构化数据,是否会出现类似情况?当然有。
在应用程序中,当两个或多个用户更新同一对象时,例如在线商店,通常通过锁定对象来实现这种管理操作。这意味着只有一个人能赢。锁是一个巨大的痛苦来源,这不仅是因为你无法实现完全合理的并发操作,还因为你可能会遇到过时的锁,并不得不决定何时释放它们。
当多人处理数据集时,往往会发生冲突。如果没有足够的工作流程和冲突度量,经常会有人的更改被压扁,因此,数据可能开始变得不准确。从长远来看,这会导致报告、客户服务和商业智能方面的各种问题。这就是diff和patch的用武之地,用户可以在每次向数据库提交更改时看到前后状态。在这里,任何冲突都可以标记出来,人工审查可以监督这些变化,以确保长期数据的准确性。更好的数据,更好的决策。
在TerminusDB Python中使用Diff和Patch
先决条件
您需要安装TerminusDB Python客户端,请查看此处。
确保Docker容器在本地主机上运行。
在这个脚本中,我们演示了diff如何返回一个补丁对象,通过该对象,您可以应用补丁来修改一个对象,我们为TerminusDB模式、TerminusDB文档和JSON模式展示了这一点。
在USDB中,文档和模式以JSON-LD格式表示。使用diff和patch,我们可以轻松地比较任何文档和模式,以查看发生了什么变化。
让我们将文档视为Python对象:
class Person(DocumentTemplate): name: str age: int jane = Person(name="Jane", age=18) janine = Person(name="Janine", age=18)
复制
您可以直接应用差异来获得面片对象:
result_patch = client.diff(jane, janine) pprint(result_patch.content)
复制
使用patch对象(这里是result_patch),您可以查看其内容,也可以将其应用于对象,然后返回after对象。
after_patch = client.patch(jane, result_patch) pprint(after_patch) assert after_patch == janine._obj_to_dict()
复制
如您所见,after_patch对象(文档)与janine相同。您可以使用replace_document将此文档放回数据库,以提交此更改。
Diff和patch还可用于JSON-LD文档:
jane = { "@id" : "Person/Jane", "@type" : "Person", "name" : "Jane"} janine = { "@id" : "Person/Jane", "@type" : "Person", "name" : "Janine"} result_patch = client.diff(jane, janine) pprint(result_patch.content)
复制
它也不限于JSON-LD,它可以使用模式:
class Company(DocumentTemplate): name: str director: Person schema1 = WOQLSchema() schema1.add_obj("Person", Person) schema2 = WOQLSchema() schema2.add_obj("Person", Person) schema2.add_obj("Company", Company) result_patch = client.diff(schema1, schema2) pprint(result_patch.content)
复制
请注意,diff和patch将适用于大多数JSON格式。
另一个应用程序示例是比较2个JSON模式:
schema1 = { "type": "object", "properties": { "name": { "type": "string" }, "birthday": { "type": "string", "format": "date" }, "address": { "type": "string" }, } } schema2 = { "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, "birthday": { "type": "string", "format": "date" }, "address": { "type": "object", "properties": { "street_address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "country": { "type" : "string" } } } } } result_patch = client.diff(schema1, schema2) pprint(result_patch.content)
复制
请参阅此处的完整脚本
在MongoDB中使用Diff和Patch
在这个脚本中,我们演示了如何在MongoDB工作流中使用diff和patch。脚本的第一部分是关于如何使用Pymongo的MongoDB教程,在第二部分中,我们演示了在将修补程序应用到MongoDB集合之前检查更改的额外步骤。
正如我们在上一节中发现的,diff和patch可以应用于任何JSON格式。由于MongoBD也使用JSON格式来描述其数据,我们可以使用diff和patch来做类似的事情。
这里我们以Pymongo教程为例:
client = MongoClient(os.environ["MONGO_CONNECTION_STRING"]) # Create the database for our example (we will use the same database throughout the tutorial connection = client['user_shopping_list'] collection_name = connection["user_1_items"] item_1 = { "_id" : "U1IT00001", "item_name" : "Blender", "max_discount" : "10%", "batch_number" : "RR450020FRG", "price" : 340, "category" : "kitchen appliance" } item_2 = { "_id" : "U1IT00002", "item_name" : "Egg", "category" : "food", "quantity" : 12, "price" : 36, "item_description" : "brown country eggs" } collection_name.insert_many([item_1,item_2]) expiry_date = '2021-07-13T00:00:00.000' expiry = dt.datetime.fromisoformat(expiry_date) item_3 = { "item_name" : "Bread", "quantity" : 2, "ingredients" : "all-purpose flour", "expiry_date" : expiry } collection_name.insert_one(item_3)
复制
假设我们想要更改item_ 1:
new_item_1 = { "_id" : "U1IT00001", "item_name" : "Blender", "max_discount" : "50%", "batch_number" : "RR450020FRG", "price" : 450, "category" : "kitchen appliance" }
复制
我们可以将新旧项目1与差异和补丁进行比较:
tbd_endpoint = WOQLClient("http://localhost:6363/") # Find the item back from database in case someone already changed it item_1 = collection_name.find_one({"item_name" : "Blender"}) patch = tbd_endpoint.diff(item_1, new_item_1) pprint(patch.content)
复制
同样,我们可以在MongoDB进行更改之前查看:
collection_name.update_one(patch.before, {"$set": patch.update})
复制
这是另一个更复杂的例子:
expiry_date = '2021-07-15T00:00:00.000' expiry = dt.datetime.fromisoformat(expiry_date) new_item_3 = { "item_name" : "Bread", "quantity" : 5, "ingredients" : "all-purpose flour", "expiry_date" : expiry } item_3 = collection_name.find_one({"item_name" : "Bread"}) item_id = item_3.pop('_id') # We want to pop it out and optionally we can add it back patch = tbd_endpoint.diff(item_3, new_item_3) pprint(patch.content) # Add _id back, though it still works without before = patch.before before['_id'] = item_id collection_name.update_one(before, {"$set": patch.update})
复制
在MongoDB JavaScript中使用Diff和Patch
与上一节一样,可以使用diff和patch来比较文档和模式,以查看使用JavaScript客户端所做的更改。
在这个脚本中,我们将演示它。
我们创建了一个名为patchMongo的函数:
const mongoPatch = function(patch){ let query = {}; let set = {}; if('object' === typeof patch){ for(var key in patch){ const entry = patch[key]; if( entry['@op'] == 'SwapValue'){ query[key] = entry['@before']; set[key] = entry['@after']; }else if(key === '_id'){ query[key] = ObjectId(entry); }else{ let [sub_query,sub_set] = mongoPatch(entry); query[key] = sub_query; if(! sub_set === null){ set[key] = sub_set; } } } return [query,set] }else{ return [patch,null] } }
复制
我们创建了一个对象,可以放回去更新MongoDB中的数据:
let patchPromise = client.getDiff(jane,janine,{}); patchPromise.then( patch => { let [q,s] = mongoPatch(patch) console.log([q,s]); const res = db.inventory.updateOne(q, { $set : s}); console.log(res); if (res.modifiedCount == 1){ console.log("yay!") }else{ console.log("boo!") } console.log(patch); });
复制
原文标题:Compare JSON Documents and Apply Patches With TerminusDB and MongoDB
原文作者:Oliver Smith
原文链接:https://dzone.com/articles/compare-json-documents-and-apply-patches-with-term