I'm working with this JSON (part of a larger JSON code):
group='{ "129": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 129 } }'
First I get the top-level key (here "129"
), which can actually be any number:
key=`echo $group | jq 'keys[0]'` # "129"
I want to change this key to a different number named nextID
which I got from another entry in the larger JSON:
nextID=`echo $groups_meta | jq '.nextID'` # 130
Now here is the problem. I am able to change the key with the following filter, but this seems to me rather fragile and complex:
new_group=`echo $group | jq --arg key $key --arg nextID $nextID 'with_entries( if .key | contains($key) then .key |= "$nextID" else . end)'`
You see that the filter finds the key by searching for the name. That may be a problem if there's another key later on with the same name. That's fragile. And this method seems rather complex; I'd really like to get the key (as in keys[0]
above) and use that for the change, all in the same filter.
So there's my question: is there a way to combine both parts, and get the key without searching?
UPDATE
Sample inputs:
group='{ "129": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 129 } }'
nextID=130
jq command:
new_group=`echo $group | jq --arg nexID $nextID 'filter'`
Expected output:
echo $new_group
{ "130": { "bounds": { "left": 20, "top": 20, "width": 250, "height": 200 }, "slot": 88, "userSize": null, "stackTabs": true, "showThumbs": true, "showUrls": true, "tileIcons": true, "catchOnce": true, "catchRules": "", "title": "", "id": 130 } }
Note that the first key "129"
should be addressed by position, similar to keys[0]
as shown above, as the number is not known beforehand. The value of key id
is also set to "130"
. Both should be set with the bash variable $nextID
imported into jq.
UPDATE 2
Using @jq170727's answer I added a few value changes after nextID
successfully, but there's an issue changing the .title value in the same input to a string with spaces:
title="new title"
new_group=`echo $group | jq --arg nextID $nextID --arg title $title '(keys_unsorted|first) as $i | with_entries(if .key == $i then .key=$nextID | .value.id=$nextID | .value.title=$title else . end)'`
This throws an error:
jq: error: title/0 is not defined at <top-level>, line 1:
title
Quoting the title variable in the jq command .value.title="$title"
also errors out. If title has no spaces in bash, the command works.
Am I missing a trick to update values with variables containing spaces? Should I ask a new question?