3

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?

peak
  • 105,803
  • 17
  • 152
  • 177
MLu
  • 1,218
  • 2
  • 15
  • 28

2 Answers2

2

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
Inian
  • 80,270
  • 14
  • 142
  • 161
  • That's great! Is there a similarly concise way for JQ 1.5? It says `jq: error: IN/1 is not defined at ` – MLu Jul 02 '21 at 05:42
  • @MLu: IN is nothing but this simple function - You can use that instead - https://github.com/stedolan/jq/blob/master/src/builtin.jq#L274 – Inian Jul 02 '21 at 05:45
  • So I changed it to `select( .Key | any($TAGS[] == .; .) )` but that still doesn't work in 1.5. The same still works in 1.6 though. – MLu Jul 02 '21 at 05:49
  • @MLu: You can adopt an approach from here - https://stackoverflow.com/q/43259563/5291015 – Inian Jul 02 '21 at 05:50
  • I saw that answer before but still can't work it out. Will update our pipeline to jq 1.6, that'll be easier. I admit that jq for me is one of those magic things that I copy&paste without much understanding. I know I know... – MLu Jul 02 '21 at 05:58
2

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)
' 
peak
  • 105,803
  • 17
  • 152
  • 177