Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

compare 2 json arrays and return the difference

Tags:

json

bash

jq

We have a custom CD Pipeline Tool, which unfortunately does not version the deployment parameters. So I put these in a Bitbucket Repo as a json file and validate them against a REST API of this CD Tool.

So I have 2 json arrays, which are structurally the same, but may contain different objects or values in these objects. I want to compare them to see if they are different and what is different.

So far, I used the solution from here: Using jq or alternative command line tools to diff JSON files

So I have put this in my code:

jq --argjson a "${bb_cfg}" --argjson b "${cd_tool_cfg}" -n 'def post_recurse(f): def r: (f | select(. != null) | r), .; r; def post_recurse: post_recurse(.[]?); ($a | (post_recurse | arrays) |= sort) as $a | ($b | (post_recurse | arrays) |= sort) as $b | $a == $b'

now I get a true if they are identical or false if 2 jsons have differences, but I do not know what is different.

I tried to do this with this if I get false back:

diff --suppress-common-lines -y <(jq . -S <<< "${bb_cfg}") <(jq . -S <<< "${cd_tool_cfg}")

Input $bb_cfg:

[{
    "key": "IGNORE_VALIDATION_ERROR",
    "value": "true",
    "tags": []
},
{
    "key": "BB_CFG_REPO_NAME",
    "value": "cd-tool-cfg",
    "tags": []
}]

Input $cd_tool_cfg

[{
    "key": "IGNORE_VALIDATION_ERROR",
    "value": "false",
    "tags": []
},
{
    "key": "BB_CFG_REPO_NAME",
    "value": "cd-tool-cfg",
    "tags": []
}]

which works partly, because if only the value is different, the output is like this:

    "value": "true"                       |     "value": "false"

so I do not get the whole json object here to quickly find out what parameter is different.

What I eventually want is to get something like this:

{
    "key": "IGNORE_VALIDATION_ERROR",
    "value": "true",
    "tags": []
}
{
    "key": "IGNORE_VALIDATION_ERROR",
    "value": "false",
    "tags": []
}

where I can store this in a variable in my bash script and transform this in an output I can use.

like image 968
Unfaced Avatar asked Apr 10 '19 06:04

Unfaced


People also ask

How do I compare two JSON outputs?

Comparing json is quite simple, we can use '==' operator, Note: '==' and 'is' operator are not same, '==' operator is use to check equality of values , whereas 'is' operator is used to check reference equality, hence one should use '==' operator, 'is' operator will not give expected result.

Can we compare two JSON objects?

Similarly, we can also compare two JSON objects that contain a list element. It's important to know that two list elements are only compared as equal if they have the same values in the exact same order.

What is a JSON diff?

A diff takes two JSON objects and presents any differences between them. Diff has several uses. A key use is displaying a clear summary of differences between large objects, enhancing the visibility of changes.


1 Answers

You could use jq's -c or --compact-output option:

diff <(jq -c .[] <<<"$bb_cfg") <(jq -c .[] <<<"$cd_tool_cfg")
1c1
< {"key":"IGNORE_VALIDATION_ERROR","value":"true","tags":[]}
---
> {"key":"IGNORE_VALIDATION_ERROR","value":"false","tags":[]}

The -c option will simply output a json with each array member on a separate line.

The following command will give you something like you requested:

diff --old-line-format="%L" --unchanged-line-format="" --new-line-format="%L" <(jq -c .[] <<<"$bb_cfg") <(jq -c .[] <<<"$cd_tool_cfg") | jq

will output:

{
    "key": "IGNORE_VALIDATION_ERROR",
    "value": "true",
    "tags": []
}
{
    "key": "IGNORE_VALIDATION_ERROR",
    "value": "false",
    "tags": []
}
like image 82
KamilCuk Avatar answered Oct 22 '22 15:10

KamilCuk