JSON Object Diff

Is there a way to easily show what key values do not match between two JSON objects? If I have two objects with the same keys, can I output just the keys and values that do not match between the two objects? I am looking for a way to do this without having to create an equality expression for each key.

Have you tried the Diff Snap?

I think the Diff snap is for comparing streams of documents and not specifically two documents or two objects in a document. I know I can easily tell if the two objects differ but I want to be able to easily tell what key values or fields differ within the two objects. If two key names are the same but their values are not then the key name and differing values would be in the output document. I’m not sure how to do that without a comparison expression for each key/field, which is tedious and not self-maintained if the keys/fields of the objects change.

Can you provide some sample data on what are we trying to achieve here.

I want to compare the prev_excptn.body object to the next_excptn.body object in the following example and create the output at the bottom showing the differences in the two.

[{
"dime_id": 10202,
"deleted_flag": false,
"start_dt": {
	"_snaptype_localdatetime": "2017-05-09T19:31:33.000"
},
"prev_excptn": {
	"body": {
		"id": 44,
		"eModel": {
			"id": 104,
			"eType": {
				"id": 56
			},
			"name": "Thing"
		},
		"sN": "00000064",
		"objectA": {
			"eId": 32,
			"mK": "werfewfe",
			"aUserId": 36,
			"aDateTime": {
				"dateTime": "2017-05-10T13:49:22+0000",
				"zone": "UTC"
			}
		}
	},
	"created": {
		"dateTime": "2017-05-10T13:49:21+0000",
		"zone": "UTC"
	}
},
"next_excptn": {
	"body": {
		"id": 44,
		"eModel": {
			"id": 104,
			"eType": {
				"id": 9999999999
			},
			"name": "Thing"
		},
		"sN": "00000064"
	},
	"created": {
		"dateTime": "2017-05-10T14:03:21+0000",
		"zone": "UTC"
	}
}

}]


The output would be something like this. I’m not set on this structure. I just want to only include the fields that didn’t match and their values. I used DNE on the next_excptn to show it Does Not Exist.

[{
"diff": {
	"body": {
		"eModel": {
			"eType": {
				"id": {
					"prev_excptn": 56,
					"next_excptn": 9999999999
				}
			}
		},
		"objectA": {
			"prev_excptn": {
				"eId": 32,
				"mK": "werfewfe",
				"aUserId": 36,
				"aDateTime": {
					"dateTime": "2017-05-10T13:49:22+0000",
					"zone": "UTC"
				}
			},
			"next_excptn": "DNE"
		}
	}
}

}]

I have spent a lot of time on this and am not yet done. It is tricky when fields don’t exist or they are many levels deep.

I have code that can do this in javascript, although for arrays it is checking differences by index so you would need to be aware of that. I would think this code snippet could be adapted to run in a script snap and get the output you desire. I put in the two objects from your example into the little utility code I had and it found the differences, would just need to modify the output formatting to what you specified.

Function -

self.internalFindDifference = function(obj1, obj2, parent, accum) {
    var result = accum || { "changes": [] };
                
    for (key in obj1) {
        if (!obj2.hasOwnProperty(key)) {
            result.changes.push({ "field": parent ? parent + "." + key : key, "type": "add", "value": obj1[key] });                       
        } else if (!_.isEqual(obj1[key],obj2[key]) && typeof obj1[key] == 'object' && typeof obj2[key] == 'object') {
            var newParent = parent ? parent + "." + key : key;
            arguments.callee(obj1[key], obj2[key], newParent, result);
        } else if (!_.isEqual(obj1[key], obj2[key])) {
            result.changes.push({ "field": parent ? parent + "." + key : key, "type": "change", "fromValue": obj2[key], "toValue": obj1[key] });
        }
    }
                
    for (key in obj2) {
        if (!obj1.hasOwnProperty(key)) {
            result.changes.push({ "field": parent ? parent + "." + key : key, "type": "delete", "fromValue": obj2[key] });                        
        }
    }

    return result;
}

Example calling code -

var result = self.internalFindDifference(obj1, obj2, null, null);
Console.log(JSON.stringify(result, null, 4));

Thank you! I was hoping there was a way to do this without scripting since it seems like a common use case for SnapLogic but I will have to give it a try!

It is not a common usage. Deep level object nesting and comparison within those depths is a very uncommon scenario.

Well, how about just top-level comparison? If I had only one level, would that be easier?

I’m using this sort of as change data capture - I want to know the differences of unknown structures so I know what to change without having to know every field ahead of time and map it and then modify the pipeline every time there is a change in structure of the two objects to compare. Is this not something SnapLogic is meant to do? I’m honestly asking, not being combative.