in place edit, search for nested value and then replace another value

70 Views Asked by At

I have an input JSON document with roughly the following form (actual data has additional keys, which should be passed through unmodified; the whitespace is adjusted for human readability, and there's no expectation that it be maintained):

{
    "Rules": [
        {"Filter": { "Prefix": "to_me/" },   "Status": "Enabled" }, 
        {"Filter": { "Prefix": "from_me/" }, "Status": "Enabled" }, 
        {"Filter": { "Prefix": "__bg/" },    "Status": "Enabled" }
    ]
}

I need to match .Rules[].Filter.Prefix=="to_me/" and then change the associated "Status": "Enabled" to "Disabled". Since only the first rule above has a prefix of to_me/, status of that rule would be changed to Disabled, making correct output look like the following:

{
    "Rules": [
        {"Filter": { "Prefix": "to_me/" },   "Status": "Disabled" }, 
        {"Filter": { "Prefix": "from_me/" }, "Status": "Enabled" }, 
        {"Filter": { "Prefix": "__bg/" },    "Status": "Enabled" }
    ]
}

I've tried several different combinations but can't seem to get it right.

Anyone have ideas?

2

There are 2 best solutions below

0
On

Doing in-place updates can be done with |=, and deciding whether to modify content in-place can be done with if/then/else. Thus:

jq '.Rules[] |= (if .Filter.Prefix == "to_me/" then .Status="Disabled" else . end)'
0
On

I prefer the idiom ARRAY |= map(...) over ARRAY[] |= ..., mainly because the former can be used reliably whether or not any of the substitutions evaluate to empty:

jq '.Rules |= map(if .Filter.Prefix == "to_me/" 
                  then .Status="Disabled" else . end)'

To overwrite the input file, you might like to consider sponge from moremutils.