Invisible999
Invisible999

Reputation: 577

jq - select and filter only certain objects from the array

My JSON file has the following structure

[
    {
        "Header": {
            "Tenant": "T1"
        },
        "Body": [
            {
                "agentTechnologyType": "JAVA",
                "entityId": "SERVICE-EDA448F07EDBDAA6",
                "serviceType": "WebRequest",
                "webServerName": "www.example.com:443"
            },
            {
                "agentTechnologyType": "TOMCAT",
                "entityId": "SERVICE-728B1FF49D132C89",
                "serviceType": "WebRequest",
                "webServerName": "www.example.com:80"
            },
            {
                "agentTechnologyType": "JAVA",
                "entityId": "SERVICE-42A0FB8666B36EB4",
                "serviceType": "Process"
            },
            {
                "agentTechnologyType": "APACHE",
                "serviceType": "WebRequest",
                "webServerName": "www.example.com:443"
            }
        ]
    }
]

I need to apply several filters and leave in the .Body[] array objects according to different criteria:

  1. Only select these objects in the .Body[] array which do not have .webServerName key present - this condition should leave only the object #2 inside the .Body[] array
  2. Only select these objects in the .Body[] array where .webServerName value is www.example.com:443 - that should leave objects # 0,3.
  3. Select all objects which have .webServerName key present, so negating the condition #1 - this should leave all object except #2.

For #1 the filter below does the job

[.[].Header as $x |  (.[].Body[] | select( (.webServerName == null  ))) as $y | {Tenant: $x, Body: [$y]} ]

It gives the following output:

[
  {
    "Tenant": {
      "Tenant": "T1"
    },
    "Body": [
      {
        "agentTechnologyType": "JAVA",
        "entityId": "SERVICE-42A0FB8666B36EB4",
        "serviceType": "Process"
      }
    ]
  }
]

But when I tried to modify the filter for the condition #2

[.[].Header as $x |  (.[].Body[] | select( (.webServerName == "www.example.com:443"  ))) as $y | {Tenant: $x, Body: [$y]} ] 

This gave me the following output - two entries instead of having one.

[
  {
    "Tenant": {
      "Tenant": "T1"
    },
    "Body": [
      {
        "agentTechnologyType": "JAVA",
        "entityId": "SERVICE-EDA448F07EDBDAA6",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:443"
      }
    ]
  },
  {
    "Tenant": {
      "Tenant": "T1"
    },
    "Body": [
      {
        "agentTechnologyType": "APACHE",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:443"
      }
    ]
  }
]

While the expected output should look like for case #2:

[
  {
    "Tenant": {
      "Tenant": "T1"
    },
    "Body": [
      {
        "agentTechnologyType": "JAVA",
        "entityId": "SERVICE-EDA448F07EDBDAA6",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:443"
      },
      {
        "agentTechnologyType": "APACHE",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:443"
      }
    ]
  }
]

And the following for case #3:

[
  {
    "Header": {
      "Tenant": "T1"
    },
    "Body": [
      {
        "agentTechnologyType": "JAVA",
        "entityId": "SERVICE-EDA448F07EDBDAA6",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:443"
      },
      {
        "agentTechnologyType": "TOMCAT",
        "entityId": "SERVICE-728B1FF49D132C89",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:80"
      },
      {
        "agentTechnologyType": "APACHE",
        "serviceType": "WebRequest",
        "webServerName": "www.example.com:443"
      }
    ]
  }
]

I am trying to figure out where I made an error - in the selection condition or in the forming of the new object at the end.

Upvotes: 2

Views: 6399

Answers (1)

Inian
Inian

Reputation: 85530

Judging from your requirements, it seems you need an expression to select objects in the .Body[] array where .webServerName key is www.example.com:443 or the key basically exists

.[].Body |= map(select(.webServerName == "www.example.com:443" or has("webServerName") ))

Both your attempts though valid are really convoluted. The standard pattern to selectively filter out objects inside the array is to use the |= operator with the right select expression.

The | {Tenant: $x, Body: [$y]} is wrong, because it is applied to each of the 2 objects you filtered in the previous expression. So each of the result has a Tenant field created. Since you have no change in key names (same key Tenant), there is really no purpose to re-create new objects with {..}.

Upvotes: 1

Related Questions