Add values to a JSON array if outer array's name == 'something'

Viewed 108

I'm passing a JSON object to jq and want to add extra objects to an inner array ('accessories') if its parent array ('platforms') matches a certain name.

Here's my source JSON:

    {
        "bridge": {
            "name": "Homebridge",
            "port": 51395
        },
        "accessories": [],
        
        "platforms": [
            {
                "name": "Config",
                "port": 8581,
                "platform": "config"
            },
            {
                "platform": "homebridge-cbus.CBus",
                "name": "CBus",
                "client_ip_address": "127.0.0.1",
                "accessories": [
                    {
                      "values": "existing"
                    }
                ]
            }
        ]
    } 

This works beautifully:

    jq '.platforms[1].accessories +=  [{ "values" : "NEW" }]'

... but of course it's poor form to expect platforms[1] to always the be array I want to append to, so I set about trying to form the right syntax for a search or if/then/else to only act on the .name of the appropriate one.

I thought this was my solution:

    jq '.platforms[] | if ( .name=="CBus" ) then .accessories += [{ "values" : "NEW" }] else . end'

... until I realised it was only passing the 'platforms' through and eating the 'bridge' object and empty outer 'accessories' array, which I need to retain.

My issue looks to be similar to JQ | Updating array element selected by `select`, but I've tried LOTS of combinations but just can't break through.

Edit: Here's the correct JQPlay I've been working with:

https://jqplay.org/s/dGDswqAEte

Thanks for any help.

1 Answers

That's a good attempt. The key here is to use the select() function to identify the object you are going to update and overwrite the overall array using |= operator, i.e.

.platforms |= ( map(select(.name == "CBus").accessories += [{ "values" : "NEW" }]  ) )

For the snippet in your jq-play link (now removed), you need to do

.gcp_price_list."CP-COMPUTEENGINE-OS" 
    |= with_entries(select(.value.cores == "shared").value.cores = "0.5")

Or if you want to be even more specific, and keep the entry in gcp_price_list configurable, do

.gcp_price_list |= 
with_entries ( 
  select(.key == "CP-COMPUTEENGINE-OS").value  |=  
with_entries(
  select(.value.cores == "shared").value.cores = "0.5") )
Related