skip to Main Content

I have ideal JSON:

{
    "environments":[
        {
            "name":"test",
            "release":"2.0"
        },
        {
            "name":"prod",
            "release":"1.0"
        },
    ]
}

This file could be in any state:

  1. It can be empty file with just empty object { }
  2. It can have empty "environemnts" array
  3. It can have some entries in environment array but not the one we want to update

I need to update or create the "release" tag with given version under given environment.

I tried variations of:

(.environments[] | select(.name == "prod") | .release) = "3.0" // .environments += [{"name": "prod", "release": "3.0"}]

I also tried:

.environments
|=  (map(.name) | index("prod")) as $ix
    | if $ix 
      then .[$ix]["release"] = "2.0" 
      else . + [{name: "release", value: "2.0"}]
      end

But it either fails on empty file. Or doesn’t create new entry.
I’m lost here.

2

Answers


  1. You can add the new element everywhere and then delete the old prod release if it existed:

    jq --arg release 1.2 '.environments += [{"name":"prod","release":$release}]
                          | del(.environments[]
                                | select(.name == "prod" and .release != $release))' file.json
    

    Tested on the following 4 files:

    echo '{}' > 1.in
    echo '{"environments":[]}' > 2.in
    echo '{"environments":[{"name":"test","release":"2.0"}]}' > 3.in
    echo '{"environments":[{"name":"test","release":"2.0"},{"name":"prod","release":"1.0"}]}' > 4.in
    
    Login or Signup to reply.
  2. You could create an INDEX, then update the .prod field. This way, it is either updated if it existed, or created if it didn’t. Afterwards, iterate over the items to restore the array. Using the ? operator when creating the stream takes care of the empty object case.

    .environments |= [
      INDEX(.[]?; .name) | .prod = {name: "prod", release: "2.0"} | .[]
    ]
    

    This turns both {} and {"environments": []} into:

    {
      "environments": [
        {
          "name": "prod",
          "release": "2.0"
        }
      ]
    }
    

    And updates the given sample (after removing the abundant comma) into:

    {
      "environments": [
        {
          "name": "test",
          "release": "2.0"
        },
        {
          "name": "prod",
          "release": "2.0"
        }
      ]
    }
    

    Demo

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search