ansiblejq

Ansible compare two JSON responses


I'm using Ansible to call the same administration API on two different servers and then selecting the core details of the applications from the responses using jq.

According to Ansible type_debug the registered variables are of type dict

ok: [localhost] => {
    "node1_applications | type_debug": "dict"
}
ok: [localhost] => {
    "node2_applications | type_debug": "dict"
}

The JSON from the two responses looks like

{
  "Node": "ESB1",
  "AppCoreDetails": [
    {
      "ApplicationName": "APP_Config_V1",
      "LastModified": "2023-08-25 12:23:26"
    },
    {
      "ApplicationName": "APP_Intervals_V1",
      "LastModified": "2022-11-23 14:46:58"
    }
  ]
}
{
  "Node": "ESB2",
  "AppCoreDetails": [
    {
      "ApplicationName": "APP_Config_V1",
      "LastModified": "2023-08-25 12:03:30"
    },
    {
      "ApplicationName": "APP_Intervals_V1",
      "LastModified": "2022-11-23 14:46:58"
    }
  ]
}

Where the LastModified date of the first entry in AppCoreDetails is different and for the second entry it's the same.

I'd like to get the set of objects where the LastMofified dates are different.

{
  "AppCoreDetails": [
    {
      "ApplicationName": "APP_Config_V1",
      "LastModified": "2023-08-25 12:23:26"
    }
  ]
}

BTW I found and tried experimenting with this but failed to convert from simple fields to objects enter link description here


Solution

  • As you've tagged , this assumes you want to call jq with the two JSON responses as its input.

    You can read in both objects into an array using the --slurp (or -s) flag, and reduce them to the relevant values. Then, use transpose to align the items, and filter for differences using select.

    jq -s '
      map(.AppCoreDetails) | transpose
      | {AppCoreDetails: map(select(first != last)[0])}
    '
    

    Demo

    This assumes that the .ApplicationName values are already aligned for both cases, i.e. the arrays have the same number of items and the names come in the same order. If this is not necessarily the case, specify how to deal with dangling matches. Here's an approach using JOIN and INDEX to find matching .ApplicationName values:

    jq -s 'map(.AppCoreDetails) | {AppCoreDetails: [JOIN(
      INDEX(last[]; .ApplicationName); first[]; .ApplicationName; select(first != last)[0]
    )]}'
    

    Demo

    Given the two sample inputs, both approaches output

    {
      "AppCoreDetails": [
        {
          "ApplicationName": "APP_Config_V1",
          "LastModified": "2023-08-25 12:23:26"
        }
      ]
    }