Stéphane
Stéphane

Reputation: 506

How to conditionally change multiple values on all records with jq

I managed to get what I needed, but I think I could possibly do it without having to call jq multiple times. Do you know how I can do the same with only one jq call ?

|jq -r --arg replace 'Cancelled' '.result|= map(if .is_cancelled == true then (.is_cancelled=$replace) else . end)' \
|jq -r --arg replace 'Started' '.result|= map(if .is_started == true then (.is_started=$replace) else . end)' \
|jq -r --arg replace 'Stopped' '.result|= map(if .is_started == false then (.is_started=$replace) else . end)' \
|jq -r --arg replace 'Active' '.result|= map(if .is_cancelled == false then (.is_cancelled=$replace) else . end)' 

The data passed to jq looks like this :

{
  "result": [
    {
      "id": 8893,
      "entry_time": "2020-11-04T16:02:43+01:00",
      "author_id": 24,
      "author_name": "joe",
      "host_id": 2115,
      "service_id": 0,
      "is_cancelled": false,
      "comment": "Test 5236",
      "deletion_time": null,
      "duration": 4302000,
      "end_time": "2020-12-24T13:48:22+01:00",
      "internal_id": 513,
      "is_fixed": true,
      "poller_id": 2,
      "start_time": "2020-11-04T18:48:22+01:00",
      "actual_start_time": "2020-11-18T12:08:16+01:00",
      "actual_end_time": null,
      "is_started": true
    },
    {
      "id": 8894,
      "entry_time": "2020-11-04T16:02:43+01:00",
      "author_id": 24,
      "author_name": "joe",
      "host_id": 2115,
[…]
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 999999999,
      "search": {},
      "sort_by": {
        "host.name": "DESC"
      },
      "total": 118
    }
  }
}

The result is something like that :

{
  "result": [
    {
      "id": 8893,
      "entry_time": "2020-11-04T16:02:43+01:00",
      "author_id": 24,
      "author_name": "joe",
      "host_id": 2115,
      "service_id": 0,
      "is_cancelled": "Active",
      "comment": "Test 5236",
      "deletion_time": null,
      "duration": 4302000,
      "end_time": "2020-12-24T13:48:22+01:00",
      "internal_id": 513,
      "is_fixed": true,
      "poller_id": 2,
      "start_time": "2020-11-04T18:48:22+01:00",
      "actual_start_time": "2020-11-18T12:08:16+01:00",
      "actual_end_time": null,
      "is_started": "Started"
    },
[…]

false and true values are replaced with some other values for the fields "is_started" and "is_cancelled", on all records of .result.

Is it possible to do the same change with calling jq only once ?

Upvotes: 1

Views: 173

Answers (1)

peak
peak

Reputation: 116740

You could begin by simply renaming the "--arg" variables:

jq -r --arg cancel Cancelled \
      --arg start Started    \
      --arg stop Stopped     \
      --arg replace Active '
.result|= map(if .is_cancelled == true then (.is_cancelled=$cancel) else . end)
| .result|= map(if .is_started == true then (.is_started=$start) else . end)
| .result|= map(if .is_started == false then (.is_started=$stop) else . end)
| .result|= map(if .is_cancelled == false then (.is_cancelled=$replace) else . end)
' 

The next step would be to rephrase this to avoid the repeated iterations through the array, so that the jq filter might look like this:

  .result |= 
     map(if .is_cancelled == true then (.is_cancelled=$cancel) 
         elif .is_cancelled == false then (.is_cancelled=$replace) 
         else . 
         end
         | if .is_started == true then (.is_started=$start) 
           elif .is_started == false then (.is_started=$stop) 
           else .
           end )

Potential simplification

You might also wish to consider the following, which however might be an oversimplification:

  .result |= 
     map(.is_cancelled |= if . then $cancel else $replace end
         | .is_started |= if . then $start else $stop end)

An alternative way to pass in the parameters

There are several less tedious ways to pass in the four parameters; you might like to consider this possibility, for example:

jq -r --argjson v '
    {"cancel": "Cancelled", "start": "Started", "stop": "Stopped",  "replace": "Active"}' '
  .result |= 
     map(.is_cancelled |= if . then $v.cancel else $v.replace end
         | .is_started |= if . then $v.start else $v.stop end)
'

Upvotes: 2

Related Questions