Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying array of key value in JSON jq

In case, I have an original json look like the following:

{
  "taskDefinition": {
    "containerDefinitions": [
      {
        "name": "web",
        "image": "my-image",
        "environment": [
          {
            "name": "DB_HOST",
            "value": "localhost"
          },
          {
            "name": "DB_USERNAME",
            "value": "user"
          }
        ]
      }
    ]
  }
}

And I would like to inplace modify the value for the matched key like so:

jq '.taskDefinition.containerDefinitions[0].environment[] | select(.name=="DB_USERNAME") | .value="new"' json

I got the output

{
  "name": "DB_USERNAME",
  "value": "new"
}

But I want more like in-place modify or the whole json from the original with new value modified, like this:

{
      "taskDefinition": {
        "containerDefinitions": [
          {
            "name": "web",
            "image": "my-image",
            "environment": [
              {
                "name": "DB_HOST",
                "value": "localhost"
              },
              {
                "name": "DB_USERNAME",
                "value": "new"
              }
            ]
          }
        ]
      }
    }

Is it possible to do with jq or any known workaround?

Thank you.

Updated

For anyone looking for editing multi-values, here is the approach I use

JQ=""
for e in DB_HOST=rds DB_USERNAME=xxx; do
    k=${e%=*}
    v=${e##*=}
    JQ+="(.taskDefinition.containerDefinitions[0].environment[] | select(.name==\"$k\") | .value) |= \"$v\" | "
done

jq '${JQ%??}' json

I think there should be more concise way, but this seems working fine.

like image 382
zdk Avatar asked Jan 04 '19 12:01

zdk


People also ask

Can jq modify JSON?

jq is equally useful for updating existing JSON data.

How do you pass variables in jq?

Using JSON Variables in jq If you want to use variables that reference JSON objects, this can be done with the --argsjson option. Using --argjson var object will set the variable $var to object . In the example below we set the $location variable to a JSON object, and nest this object into our results.

What is jq slurp?

“Slurp” tells jq to read every line of the input JSON lines and treat the entire group as one huge array of objects. With the Twitter data still in the input box on jq play, check the “Slurp” box, and just put .

What is jq format?

jq is a free open source JSON processor that is flexible and straightforward to use. It allows users to display a JSON file using standard formatting, or to retrieve certain records or attribute-value pairs from it.


2 Answers

It is enough to assign to the path, if you are using |=, e.g.

jq '
  (.taskDefinition.containerDefinitions[0].environment[] | 
   select(.name=="DB_USERNAME") | .value) |= "new"
' infile.json

Output:

{
  "taskDefinition": {
    "containerDefinitions": [
      {
        "name": "web",
        "image": "my-image",
        "environment": [
          {
            "name": "DB_HOST",
            "value": "localhost"
          },
          {
            "name": "DB_USERNAME",
            "value": "new"
          }
        ]
      }
    ]
  }
}
like image 130
Thor Avatar answered Sep 23 '22 06:09

Thor


Here is a select-free solution using |=:

.taskDefinition.containerDefinitions[0].environment |=
  map(if .name=="DB_USERNAME" then .value = "new"
      else . end)

Avoiding select within the expression on the LHS of |= makes the solution more robust w.r.t. the version of jq being used.

like image 29
peak Avatar answered Sep 22 '22 06:09

peak