skip to Main Content

I tried this for 2 days but can’t figure it out in any way.

This is my JSON:

{
    "items": [
        {
            "name":"itemA",
            "bins":[
                {
                    "bin_id":"b1",
                    "count":"11"
                },
                {
                    "bin_id":"b2",
                    "count":"22"
                }
            ]
        },
        {
            "name":"itemB",
            "bins":[
                {
                    "bin_id":"b5",
                    "count":"55"
                }
            ]
        }
    ]
}

Important note. Input JSON could be empty object ‘{}’ or missing any part of the hierarchy.

I need to insert whole hierary or update final entry for "count". My input arguments are: itemName, binId and new count.

So for "itemA", "b1" and count 68. I need to set .items -> (item with name: "itemA") -> (bin with bin_id 68) -> count = 68.

I tried using INDEX to access items. And that works… but I can’t seem to further access bins and update final count.

UPDATE:

I got something like this:

.items |= [INDEX(.[]?;.name) | .itemA |= .+ {name:"itemA",bins:[INDEX(.bins[]?;.bin_id) | .b1 |= .+ {bin_id:"b1",count:"188000"} | .[]]} | .[]]

But it does look ugly. Can this be done more clearly?

2

Answers


  1. Given these arguments, this is the adapted, now nested approach from the previous question:

    jq --arg name itemA --arg bin_id b1 --arg count 68 '
      .items |= [INDEX(.[]?; .name) | .[$name] |= ({$name, bins}
        | .bins |= [INDEX(.[]?; .bin_id) | .[$bin_id] |= {$bin_id, $count} | .[]]
      ) | .[]]
    '
    

    Demo

    Which can be generalized by moving the repeating code into a function, and nesting the calls:

    jq --arg name itemA --arg bin_id b1 --arg count 68 '
      def f(a;b;c): .[a] |= [INDEX(.[]?; .[b|keys[]]) | .[b[]] |= b+c | .[]];
      f("items"; {$name}; f("bins"; {$bin_id}; {$count}))
    '
    

    Demo

    Both output:

    {
      "items": [
        {
          "name": "itemA",
          "bins": [
            {
              "bin_id": "b1",
              "count": "68"
            },
            {
              "bin_id": "b2",
              "count": "22"
            }
          ]
        },
        {
          "name": "itemB",
          "bins": [
            {
              "bin_id": "b5",
              "count": "55"
            }
          ]
        }
      ]
    }
    
    Login or Signup to reply.
  2. You can use select to get the object to update :

    jq --arg i itemA --arg b b1 --arg c 68 '(
        .items[]? | 
        select(.name==$i).bins[] |
        select(.bin_id==$b)
        ).count=$c' file.json
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search