8

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.

3 Answers 3

7

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"
          }
        ]
      }
    ]
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. This solution looks the most obvious to the question I had. I also do append for multi values modify based on your answer, please see the updated section in the answer.
4

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.

Comments

3

You might like to consider this alternative to using |=:

walk( if type=="object" and .name=="DB_USERNAME" 
      then .value="new" else . end)

1 Comment

Why aren't you merging your two answers?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.