'Removing and adding key-value from JSON file using jq

I have an json file as follows below-

{
  "key1": [
    "value1"
  ],
  "key2": [
    "value2"
  ],
  "key3": [
    "value3"
  ],
  "key4": {
    "name": "value4"
  },
  "key5": [
    {
      "field1": "abc",
      "field2": "xyz"
    }
  ]
}

I want to remove field 2 from key5 array and add another field say field3 in key5 array using jq I tried various way but couldn't figure it how to do this in single command. Can you please help . Thanks in advance



Solution 1:[1]

This assumes that the insert and deletion keys (field2 and field3) are also dynamic, not just the inserted value.

  • Use --arg and --argjson to initialize variables with values from outside the filter, here field2 as a string and {"field3": "new"} as a JSON object
  • Use the update operator |= on the element you want to change, here .key5[].
    • Note: .key5 is an array, not an object, thus it has no fields. But the array does contain objects as its elements. Using .key5[] to access the array elements will update all objects in the array. To update just one of them, say, the first one, use .key[0] instead.
  • Use delpaths to delete a given path, here the top-level field [$delkey].
  • Use simple addition + to add a new key/value pair as object, here $add.
jq --arg delkey 'field2' --argjson addobj '{"field3": "new"}' '
  .key5[] |= delpaths([[$delkey]]) + $addobj
' input.json
{
  "key1": [
    "value1"
  ],
  "key2": [
    "value2"
  ],
  "key3": [
    "value3"
  ],
  "key4": {
    "name": "value4"
  },
  "key5": [
    {
      "field1": "abc",
      "field3": "new"
    }
  ]
}

Demo

If you want to provide the new object's key and value separately, i.e. as strings, not as a pre-composed JSON, you need a third input variable

jq --arg delkey 'field2' --arg addkey 'field3' --arg addval 'new' '
  .key5[] |= (delpaths([[$delkey]]) | .[$addkey] = $addval)
' input.json

Demo

Solution 2:[2]

.key5[] |= ( ... ) allows you to modify each element of the array found at .key5.

Therein, we can use the usual commands for deleting and adding fields.

jq '.key5[] |= ( del( .field2 ) | .field3 = "foo" )'

Demo in jqplay

Here's a variation where the value to add is provided as a command-line argument:

jq --arg val foo '.key5[] |= ( del( .field2 ) | .field3 = $val )'

Solution 3:[3]

Try filter:

del(.key5[0].field2) | .key5[0] |= .+{field3:"foo"}

Output:

{
  "key1": [
    "value1"
  ],
  "key2": [
    "value2"
  ],
  "key3": [
    "value3"
  ],
  "key4": {
    "name": "value4"
  },
  "key5": [
    {
      "field1": "abc",
      "field3": "foo"
    }
  ]
}

Demo

https://jqplay.org/s/EB8MpWRxU2

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Logan Lee