JSON Diff and Patch Demonstration
A demonstration of using JSON Diff and Patch to monitor changes in TerminusDB schemas and documents, JSON schemas, and other document databases such as MongoDB.

Key topics

Requirements

Install a client

Install a JavaScript or Python TerminusDB client.

Use the client with TerminusDB

Install and run the docker container on localhost

Use the client with TerminusX

Or to use TerminusX, log into your account or sign-up.

Use JSON Diff and Patch with a TerminusDB client

TerminusDB represents objects such as documents and schemas in JSON-LD format. Use JSON Diff and Patch to easily compare these objects to obtain differences between them.
The Diff function returns a Patch object containing differences between the objects compared. Use Patch to implement manual or programmatic actions to resolve differences. Actions include:
  • Retain the original object.
  • Change to the new (or latest) version of the object.
  • Create a new version of the object.
The functionality above is demonstrated in three simple steps:

Define documents

For simplicity, this demonstration represents JSON documents as client objects. Two 'document' objects are defined - jane and janine.
JavaScript
Python
1
const jane = {
2
"@id": "Person/Jane",
3
"@type": "Person",
4
age: 18,
5
name: "Jane",
6
};
7
8
const janine = {
9
"@id": "Person/Jane",
10
"@type": "Person",
11
age: 18,
12
name: "Janine",
13
};
Copied!
1
class Person(DocumentTemplate):
2
name: str
3
age: int
4
5
jane = Person(name="Jane", age=18)
6
janine = Person(name="Janine", age=18)
Copied!

Compare documents

Apply the diff function to jane and janine to populate the patch objectresult_patch. View the contents of result_patch to see any differences.
JavaScript
Python
1
const result_patch = await client.getDiff(jane, janine);
2
3
console.log(result_patch);
Copied!
1
result_patch = client.diff(jane, janine)
2
3
pprint(result_patch.content)
Copied!

Implement actions

After patch

Use the patch function to apply result_patch to the document jane. The object after_patch contains a copy of jane after the patch is applied.
Use after_patch to suit your requirements. The following example compares the modified jane document to the original janine document.
JavaScript
Python
1
const after_patch = await client.patch(jane, result_patch);
2
3
console.log(after_patch);
4
5
console.log(JSON.stringify(after_patch) === JSON.stringify(janine));
Copied!
1
after_patch = client.patch(jane, result_patch)
2
3
pprint(after_patch)
4
5
assert after_patch == janine._obj_to_dict()
Copied!

Replace/update document

If there are differences between the two documents, you may wish to replace one document with the other. Use replace document functionality for this.

Use JSON Diff and Patch with MongoDB

An example in four simple steps demonstrating the use JSON Diff and Patch with another JSON-compliant database - MongoDB:

Insert items into a MongoDB database

Create a new MongoDB database and insert three items - item_1 to item_3 into a collection object.
JavaScript
Python
1
const { MongoClient } = require("mongodb");
2
3
// Connection URL
4
const url = "mongodb://localhost:27017";
5
const client = new MongoClient(url);
6
7
// Database Name
8
const dbName = "user_shopping_list";
9
10
async function main() {
11
// Use connect method to connect to the server
12
await client.connect();
13
console.log("Connected successfully to server");
14
15
// Create the database for our example (we will use the same database throughout the tutorial
16
const db = client.db(dbName);
17
const collection = db.collection("user_1_items");
18
19
let item_1 = {
20
_id: "U1IT00001",
21
item_name: "Blender",
22
max_discount: "10%",
23
batch_number: "RR450020FRG",
24
price: 340,
25
category: "kitchen appliance",
26
};
27
28
const item_2 = {
29
_id: "U1IT00002",
30
item_name: "Egg",
31
category: "food",
32
quantity: 12,
33
price: 36,
34
item_description: "brown country eggs",
35
};
36
const insertResult = await collection.insertMany([item_1, item_2]);
37
console.log("Inserted documents =>", insertResult);
38
39
const item_3 = {
40
item_name: "Bread",
41
quantity: 2,
42
ingredients: "all-purpose flour",
43
expiry_date: "2021-07-13 00:00:00",
44
};
45
await collection.insertOne(item_3);
46
47
return "done";
48
}
49
50
main()
51
.then(console.log)
52
.catch(console.error)
53
.finally(() => client.close());
Copied!
1
client = MongoClient(os.environ["MONGO_CONNECTION_STRING"])
2
3
# Create the database for our example (we will use the same database throughout the tutorial
4
connection = client['user_shopping_list']
5
6
collection_name = connection["user_1_items"]
7
8
item_1 = {
9
"_id" : "U1IT00001",
10
11
"item_name" : "Blender",
12
"max_discount" : "10%",
13
"batch_number" : "RR450020FRG",
14
"price" : 340,
15
"category" : "kitchen appliance"
16
}
17
18
item_2 = {
19
"_id" : "U1IT00002",
20
"item_name" : "Egg",
21
"category" : "food",
22
"quantity" : 12,
23
"price" : 36,
24
"item_description" : "brown country eggs"
25
}
26
27
collection_name.insert_many([item_1,item_2])
28
29
expiry_date = '2021-07-13T00:00:00.000'
30
expiry = dt.datetime.fromisoformat(expiry_date)
31
item_3 = {
32
"item_name" : "Bread",
33
"quantity" : 2,
34
"ingredients" : "all-purpose flour",
35
"expiry_date" : expiry
36
}
37
collection_name.insert_one(item_3)
Copied!

Modify an item

The 'document' new_item_1 represents a modified instance of item_1 with changes to properties max_discount and price.
JavaScript
Python
1
const new_item_1 = {
2
_id: "U1IT00001",
3
item_name: "Blender",
4
max_discount: "50%",
5
batch_number: "RR450020FRG",
6
price: 450,
7
category: "kitchen appliance",
8
};
Copied!
1
new_item_1 = {
2
"_id" : "U1IT00001",
3
"item_ame" : "Blender",
4
"max_discount" : "50%",
5
"batch_number" : "RR450020FRG",
6
"price" : 450,
7
"category" : "kitchen appliance"
8
}
Copied!

Compare modified and original items

Retrieve the original item in the collection and compare it to the modified item new_item_1.
JavaScript
Python
1
const tbd_endpoint = new TerminusDBClient.WOQLClient("http://127.0.0.1:6363/", {
2
user: "admin",
3
organization: "admin",
4
key: "root",
5
});
6
7
// Find the item back from database in case someone already changed it
8
item_1 = collection.findOne({ item_name: "Blender" });
9
const patch = tbd_endpoint.getDiff(item_1, new_item_1);
10
11
console.log(patch);
Copied!
1
tbd_endpoint = WOQLClient("http://localhost:6363/")
2
3
# Find the item back from database in case someone already changed it
4
item_1 = collection_name.find_one({"item_name" : "Blender"})
5
patch = tbd_endpoint.diff(item_1, new_item_1)
6
7
pprint(patch.content)
Copied!

Update the original item

Update the orginal item in the MongoDB database. If required, review the differences prior to the update.
JavaScript
Python
Define a function patchMongo to get a patch object:
1
const mongoPatch = function(patch){
2
let query = {};
3
let set = {};
4
5
if('object' === typeof patch){
6
for(var key in patch){
7
const entry = patch[key];
8
9
if( entry['@op'] == 'SwapValue'){
10
query[key] = entry['@before'];
11
set[key] = entry['@after'];
12
}else if(key === '_id'){
13
query[key] = ObjectId(entry);
14
}else{
15
let [sub_query,sub_set] = mongoPatch(entry);
16
query[key] = sub_query;
17
if(! sub_set === null){
18
set[key] = sub_set;
19
}
20
}
21
}
22
return [query,set]
23
}else{
24
return [patch,null]
25
}
26
}
Copied!
Apply the patch:
1
let [q,s] = mongoPatch(patch);
2
console.log([q,s]);
3
4
await collection.updateOne(q, {"$set": s});
Copied!
1
collection_name.update_one(patch.before, {"$set": patch.update})
Copied!

See also

JSON Diff and Patch client functions

JavaScript client diff and patch.
Python client diff and patch.

Demonstration script

The full script for this demonstration (on GitHub.)