添加到对象列表并覆盖(如果已存在于数组中)

时间:2018-01-22 10:44:46

标签: bash jq

我有一个来自API的JSON对象,如下所示:

{
  "objectList": [
    {
      "name": "item1",
      "value": false
    },
    {
      "name": "item2",
      "value": true
    }
  ]
}

我需要在此附加项目。我可以使用jq

执行此操作
jq '.objectList += [{"name": "item3", "value": true}]' apiResponse.json

但是,有时我需要添加一个带有name属性的项目,该属性已存在于响应中,我需要使用我想要设置的新值来覆盖它的值。例如,我可能想要更改' item2'的值。到false

我已经在jq中编写了一个过滤器,以便我可以遍历objectList,但我不确定如何比较两个名称(我要添加的名称,以及循环的当前迭代中的项的名称)。这是我的循环过滤器:

jq -r '.objectList[] | [.name]

这会打印出如下数组:

[
  "extendedStatus"
]
[
  "anotherFeature"
]

然后我尝试在这个过滤器上添加一个条件:

jq -r '.objectList[] | if .name == "item1" then .value == true else .value == false end' apiResponse.json

但这只是打印出来的:

true
false

编辑 - 略微改进的过滤器:

jq -r '.objectList[] | if .name == "item1" then {name: .name, value: true} else {name: .name, value: false} end'

打印出来:

{
  "name": "item1",
  "value": true
}
{
  "name": "item2",
  "value": false
}

这种改进的过滤器效果更好,但是如果项目中没有项目(当它完成循环时),我仍然不确定如何添加项目。

有一点需要注意 - 这是在一个bash脚本中完成的,在一个方法中我有参数(项目的名称和值)。

2 个答案:

答案 0 :(得分:0)

让我们说主要的API json文件apiResponse.json

{
  "objectList": [
    {
      "name": "item1",
      "value": false
    },
    {
      "name": "item2",
      "value": true
    },
    {
      "name": "item4",
      "value": true
    }
  ]
}

我们有文件new_objects.dat中包含的新对象列表:

{"name":"item1","value":true}
{"name":"item2","value":false}
{"name":"item3","value":true}
jq --slurpfile new_items new_objects.dat \
     '.objectList |= [ . + $new_items | group_by(.name)[] | add ]' apiResponse.json

输出:

{
  "objectList": [
    {
      "name": "item1",
      "value": true
    },
    {
      "name": "item2",
      "value": false
    },
    {
      "name": "item3",
      "value": true
    },
    {
      "name": "item4",
      "value": true
    }
  ]
}

答案 1 :(得分:0)

您可以使用select过滤输入。这将选择“item2”元素:

.objectList[] | select(.name == "item2")

如果选择“item3”,上面的内容将返回null。在这种情况下,您可以使用替代运算符//来定义默认值:

(.objectList[] | select(.name == "itemX")) // {"name": "item3", "value": null}

以上将始终返回一个对象,可以通过将“value”设置为false来修改该对象:

((.objectList[] | select(.name == "itemX")) // {"name": "item3", "value": null}) | .value = false

为了获得完整列表,您必须添加与另一个选择不匹配的元素。

.objectList[] | select(.name != "itemX")

可以使用逗号和方括号连接两个列表,并将结果放入新对象中。

[
  (((.objectList[] | select(.name == "itemX")) // {"name": "item3", "value": null}) | .value = false)
  ,
  (.objectList[] | select(.name != "itemX"))
] |
{"objectList": .}