How do a create a JSON
object which shows the difference in values of each key if such exist from two different JSON
files?
This will be a long post, but mainly due to the JSON
files I am using. Please bear with me.
I have a source file - original.json
{
"billLogAnalyticsAsDavisDataUnits": false,
"billingProvider": "INTERNAL",
"blockUIDate": 1652572799000,
"chatEnabled": false,
"customMetricsLimit": 9223372036854776000,
"customMetricsOverageLimit": 9223372036854776000,
"davisDataUnitsAnnualLimit": -1,
"davisDataUnitsEnabled": false,
"davisDataUnitsMigrated": false,
"davisDataUnitsMonthlyLimit": -1,
"demUnitsAnnualQuota": 0,
"demUnitsQuota": 0,
"expirationCounterEnabled": true,
"expirationTime": 1652572799000,
"externalApiQuota": 2147483647,
"hostUnitsCapping": {
"fullstackHostLimit": 0,
"hasContainersHostLimit": 0,
"hostUnitsCappingEnabled": false,
"infrastructureOnlyHostLimit": 0
},
"hostUnitsQuota": 2147483647,
"ibmSystemZCICSIMSMonitoring": false,
"infrastructureSupportedTechnologies": {
"infrastructureOnlySupport": true,
"logAgent": true,
"maxInfrastructureOnlyAgents": 9223372036854776000,
"networkAgent": true,
"pluginAgent": true
},
"iotEntityQuota": 20,
"iotTsQuota": 10,
"isConsumption": false,
"isCreditExhausted": false,
"isRumEnabled": false,
"licenseType": "PAYING",
"logAnalyticsIngressQuota": 9223372036854776000,
"logAnalyticsIngressQuotaAnnually": 9223372036854776000,
"logAnalyticsStorageEnabled": false,
"logAnalyticsStorageQuota": 0,
"maxActionsPerMinute": 3500,
"maxAgents": 2147483647,
"maxHostUnitsQuota": -1,
"maxPaasAgents": 2147483647,
"maxWebChecks": 9223372036854776000,
"maxWebChecksAnnual": 9223372036854776000,
"overageCustomMetrics": true,
"overageEnabled": false,
"replayStorageDomQuotaInMb": 10000,
"replayStorageDomRetention": 86400000,
"retentionCode": 864000000,
"retentionRum": 864000000,
"retentionService": 1209600000,
"retentionWebcheck": 864000000,
"rumAdditionalUserPropertiesEnabled": true,
"rumAdditionalUserPropertiesLowerLimit": 20,
"sessionReplayEnabled": false,
"sessionStorageQuota": 2147483647,
"suspensionType": "NONE",
"symbolicationFileStorageQuota": 1024,
"syntheticEnabled": false,
"useHostUnitWeighting": false,
"visitsAnnualQuota": -1,
"visitsQuota": -1
}
I need to replace a number of keys having new values which are stored in the template.json file
{
"billLogAnalyticsAsDavisDataUnits": false,
"billingProvider": "INTERNAL",
"blockUIDate": 1652572799000,
"chatEnabled": false,
"demUnitsAnnualQuota": -1,
"demUnitsQuota": -1,
"isRumEnabled": false,
"licenseType": "PAYING",
"logAnalyticsIngressQuota": -1,
"logAnalyticsIngressQuotaAnnually": -1,
"logAnalyticsStorageEnabled": false,
"logAnalyticsStorageQuota": 0,
"overageCustomMetrics": true,
"overageEnabled": false,
"replayStorageDomQuotaInMb": 10000,
"replayStorageDomRetention": 86400000,
"retentionCode": 864000000,
"retentionRum": 864000000,
"retentionService": 1209600000,
"retentionWebcheck": 864000000,
"rumAdditionalUserPropertiesEnabled": true,
"rumAdditionalUserPropertiesLowerLimit": 20,
"sessionReplayEnabled": false,
"sessionStorageQuota": 102400,
"suspensionType": "NONE",
"symbolicationFileStorageQuota": 1024,
"syntheticEnabled": true,
"useHostUnitWeighting": false,
"visitsAnnualQuota": 0,
"visitsQuota": -1
}
I am using jq's following call
jq -n --argfile original.json --argfile template template.json '$original |$original +=$template' >updated.json
to get the new updated.json file with updated values and afterward to submit it to the API server.
API server after processing issues a new file with exactly the same structure. However, some key values might change. Here is the downloaded file from the API server - downloaded.json
{
"billLogAnalyticsAsDavisDataUnits": false,
"billingProvider": "INTERNAL",
"blockUIDate": 1652572799000,
"chatEnabled": false,
"customMetricsLimit": 9223372036854776000,
"customMetricsOverageLimit": 9223372036854776000,
"davisDataUnitsAnnualLimit": -1,
"davisDataUnitsEnabled": true,
"davisDataUnitsMigrated": false,
"davisDataUnitsMonthlyLimit": -1,
"demUnitsAnnualQuota": -1,
"demUnitsQuota": -1,
"expirationCounterEnabled": true,
"expirationTime": 0,
"externalApiQuota": 2147483647,
"hostUnitsCapping": {
"fullstackHostLimit": 0,
"hasContainersHostLimit": 0,
"hostUnitsCappingEnabled": false,
"infrastructureOnlyHostLimit": 0
},
"hostUnitsQuota": -1,
"ibmSystemZCICSIMSMonitoring": false,
"infrastructureSupportedTechnologies": {
"infrastructureOnlySupport": true,
"logAgent": true,
"maxInfrastructureOnlyAgents": 9223372036854776000,
"networkAgent": true,
"pluginAgent": true
},
"iotEntityQuota": 20,
"iotTsQuota": 10,
"isConsumption": false,
"isCreditExhausted": false,
"isRumEnabled": true,
"licenseType": "PAYING",
"logAnalyticsIngressQuota": -1,
"logAnalyticsIngressQuotaAnnually": -1,
"logAnalyticsStorageEnabled": false,
"logAnalyticsStorageQuota": 0,
"maxActionsPerMinute": 3500,
"maxAgents": 2147483647,
"maxHostUnitsQuota": -1,
"maxPaasAgents": 2147483647,
"maxWebChecks": 9223372036854776000,
"maxWebChecksAnnual": 9223372036854776000,
"overageCustomMetrics": true,
"overageEnabled": false,
"replayStorageDomQuotaInMb": 10000,
"replayStorageDomRetention": 86400000,
"retentionCode": 864000000,
"retentionRum": 864000000,
"retentionService": 1209600000,
"retentionWebcheck": 864000000,
"rumAdditionalUserPropertiesEnabled": true,
"rumAdditionalUserPropertiesLowerLimit": 20,
"sessionReplayEnabled": false,
"sessionStorageQuota": 102400,
"suspensionType": "NONE",
"symbolicationFileStorageQuota": 1024,
"syntheticEnabled": true,
"useHostUnitWeighting": false,
"visitsAnnualQuota": 0,
"visitsQuota": -1
}
Here is my task - I need to find the difference between the updated.json and downloaded.json
I am using diff
diff <(jq -S . update.json) <(jq -S . downloaded.json)
It produces the following result
< "davisDataUnitsEnabled": false,
---
> "davisDataUnitsEnabled": true,
15c15
< "expirationTime": 1652572799000,
---
> "expirationTime": 0,
23c23
< "hostUnitsQuota": 2147483647,
---
> "hostUnitsQuota": -1,
36c36
< "isRumEnabled": false,
---
> "isRumEnabled": true,
What I want instead - to create a new object with the original (from updated.json) and new (from downloaded.json) files, so it should look the following way:
"Original": {
"davisDataUnitsEnabled": false,
"expirationTime": 1652572799000,
"hostUnitsQuota": 2147483647,
"isRumEnabled": false
},
"Updated": {
"davisDataUnitsEnabled": true,
"expirationTime": 0,
"hostUnitsQuota": -1,
"isRumEnabled": true
}
}
I tried to use to_entries
and from_entries
see the difference between the updated and downloaded with the following jq command combining all together:
jq -n \
--argfile original original.json \
--argfile download downloaded.json \
--argfile template template.json \
'$original |$original +=$template |
($original | to_entries) as $x |
($download | to_entries) as $y |
$y - $x | from_entries'
However, the output is quite different compared to the diff:
{
"davisDataUnitsEnabled": true,
"demUnitsAnnualQuota": -1,
"demUnitsQuota": -1,
"expirationTime": 0,
"hostUnitsQuota": -1,
"isRumEnabled": true,
"logAnalyticsIngressQuota": -1,
"logAnalyticsIngressQuotaAnnually": -1,
"sessionStorageQuota": 102400,
"syntheticEnabled": true,
"visitsAnnualQuota": 0
}
Seven more keys are listed in the above output, instead of four from diff, and these seven keys have exactly the same values in the updated.json
and downloaded.json
My questions - what causes these seven additional keys to appear in the jq output? Can I get with jq a correct output of keys with differences in values and have the output formatted the way I want?
--
P.S. After some digging, figured out that comm
is giving me the output I want
comm --nocheck-order -13 <(jq -S . updated.json) <(jq -S . downloaded.json)
Which produces the output:
"davisDataUnitsEnabled": true,
"expirationTime": 0,
"hostUnitsQuota": -1,
"isRumEnabled": true,
Now if I could put that output under the "Updated"
object via JQ
while ignoring the trailing comma, that probably would be the end result...
UPDATE I figured out what was the problem and wrote the answer below. Leaving the question as is, because someone might encounter the same situation.
After posting the question, and re-checking the following jq
command, I released that I am not keeping the combined original and template files in a variable, so the original, unmodified file is assigned to the var $x
.
jq -n \
--argfile original original.json \
--argfile download downloaded.json \
--argfile template template.json \
'$original |$original +=$template |
($original | to_entries) as $x |
($download | to_entries) as $y |
$y - $x | from_entries
Instead, the correct jq
command which produces the result I wanted is the following:
jq -n \
--argfile original original.json \
--argfile download downloaded.json \
--argfile template template.json \
'$original |($original +=$template | to_entries) as $x |
($download | to_entries) as $y |
($y - $x | from_entries) as $new |
($x - $y | from_entries) as $old |
[{"Original":$old,"Updated": $new}]'
which produces the right output:
[
{
"Original": {
"davisDataUnitsEnabled": false,
"expirationTime": 1652572799000,
"hostUnitsQuota": 2147483647,
"isRumEnabled": false
},
"Updated": {
"davisDataUnitsEnabled": true,
"expirationTime": 0,
"hostUnitsQuota": -1,
"isRumEnabled": true
}
}
]