user742030
user742030

Reputation:

Modify Nested JSON with jq

I'm trying to modify nested JSON objects using the jq <map> function in a bash/shell script; something similar to this blog entry but attempting to adapt the examples here to nested objects.

The returned JSON to be modified as follows:

{
  "name": "vendor-module",
  "dependencies": {
    "abc": {
      "from": "[email protected]",
      "resolved": "https://some.special.url",
      "version": "2.4.0"
    },
    "acme": {
      "from": "[email protected]",
      "resolved": "<CHANGE_THIS>",
      "version": "1.2.3"
    }
  }
}

This would be my attempt:

modules="`node -pe 'JSON.parse(process.argv[1]).dependencies.$dependency' \
  "$(cat $wrapped)"`"
version="1.2.3"
resolved="some_url"

cat OLD.json | 
  jq 'to_entries | 
       map(if .dependencies[0].$module[0].from == "$module@$version"
          then . + {"resolved"}={"$resolved"}
          else . 
          end
         ) | 
      from_entries' > NEW.json

Obviously this doesn't work. When I run the script the NEW.json is created but without modifications or returned errors. If I don't target a nested object (e.g., "name": "vendor-module"), The script works as expected. I am sure there is a way to do it using native bash and jq..?? Any help (with the proper escaping) will be greatly appreciated.

UPDATE:

Thnx from the help of Charles Duffy's answer, and his suggestion of using sponge, The solution that works well for me is:

jq --arg mod "acme" --arg resolved "Some URL" \
   '.dependencies[$mod].resolved |= $resolved' \
   OLD.json | sponge OLD.json

Upvotes: 0

Views: 3204

Answers (2)

Jeff Mercado
Jeff Mercado

Reputation: 134811

If you know the name of the dependency you want to update, you could just index into it.

$ jq --arg dep "$dep" --arg resolved "$resolved" \
    '.dependencies[$dep].resolved = $resolved' \
    OLD.json > NEW.json

Otherwise, to modify a dependency based on the name (or other property), search for the dependency and update.

$ jq --arg version "$version" --arg resolved "$resolved" \
    '(.dependencies[] | select(.version == $version)).resolved = $resolved' \
    OLD.json > NEW.json

Upvotes: 2

Charles Duffy
Charles Duffy

Reputation: 295278

For your existing sample data, the following suffices:

jq --arg mod "acme" \
   --arg resolved "some_url" \
  '.dependencies[$mod].resolved=$resolved' \
  <in.json >out.json

...to filter on the from, by contrast:

jq --arg new_url "http://new.url/" \
   --arg target "[email protected]" \
  '.dependencies=(.dependencies
                  | to_entries
                  | map(if(.value.from == $target)
                        then .value.resolved=$new_url
                        else . end)
                  | from_entries)' \
  <in.json >out.json

Upvotes: 0

Related Questions