JQ checking for values in an array given as a parameter

Viewed 141

I've got a simple JQ filter to update some values in an array based on the "Key", for example this is my input:

[
    {
        "Key": "IDontCare",
        "Value": "something"
    },
    {
        "Key": "Tag1",
        "Value": "123-456"
    },
    {
        "Key": "Tag2",
        "Value": "121-717"
    }
]

I want to update both tags to a new value (same value for both), so I've got this command, that works:

jq --arg NEW_VALUE '987-654' \
    '[.[] |= if(.Key=="Tag1" or .Key=="Tag2") then (.Value=$NEW_VALUE) else . end]'

However I want to update different tags in different runs and would like to pass them as another argument. But not sure how to change the if() to look up the tags from the parameter.

I tried something like this but that's apparently not the right way:

jq --argjson TAGS '["Tag1","Tag2"]' --arg NEW_VALUE '987-654' \
    '[.[] |= if(.Key|in($TAGS)) then (.Value=$NEW_VALUE) else . end]'

Any ideas?

2 Answers

You can use IN to see if the value is part of the list and use a much simpler update assignment using select as

jq --arg NEW_VALUE '987-654' --argjson TAGS '["Tag1","Tag2"]' '
   map(select( .Key | IN($TAGS[] ) ).Value |= $NEW_VALUE )' json

With jq 1.5 or later

jq --arg NEW_VALUE '987-654' --argjson TAGS '["Tag1","Tag2"]' '
   def IN(s): first((s == .) // empty) // false;
   map(if .Key | IN($TAGS[]) then .Value = $NEW_VALUE else . end)
'

(With jq 1.6, you can obviously leave out the def of IN/1.)

With jq 1.4 or later

jq --arg NEW_VALUE '987-654' --arg TAGS '["Tag1","Tag2"]' '
   ($TAGS|fromjson) as $TAGS
   | map(if [.Key == $TAGS[]]|any then .Value = $NEW_VALUE else . end)
' 
Related