仅需一次通过shell数组的输入即可修改JSON数组

时间:2018-12-22 14:52:57

标签: arrays json bash jq

是否可以仅通过一次过滤JQ中的整个项目数组?比较下面的代码,它们反复运行jq

{
      "foofoo": {
        "barbar": [
          {
            "foo": "aaaa",
            "bar": 0000
          },
          {
            "foo": "bbbb",
            "bar": 1111
          },
          {
            "foo": "cccc",
            "bar": 2222
          }
          ]
      }
}

bash数组:

array=("1111" "2222")

我的代码正在运行,但效率不是很高,考虑到实际的数组大小,它使用了大量资源:

for k in "${array[@]}"; do 
    jq  --argjson k "$k"  '.foofoo.barbar |= map(select(.bar != $k))' json.json | sponge json.json 
done

它不断循环遍历数组,删除不需要的条目并使用海绵再次存储相同的文件。

有什么想法可以用更简单的代码实现类似的行为?

所需的输出:

{
  "foofoo": {
    "barbar": [
      {
        "foo": "aaaa",
        "bar": 0
      }
    ]
  }
}

3 个答案:

答案 0 :(得分:2)

要显着提高性能,请使用以下jq方法(不使用任何 shell 循环):

arr=("1111" "2222")
jq '($p | split(" ") | map(tonumber)) as $exclude 
    | .foofoo.barbar 
      |= map(select(.bar as $b 
                    | any($exclude[]; . == $b) | not))' \
    --arg p "${arr[*]}" file.json | sponge file.json

输出:

{
  "foofoo": {
    "barbar": [
      {
        "foo": "aaaa",
        "bar": 0
      }
    ]
  }
}

答案 1 :(得分:1)

我很肯定有更好的方法可以做到这一点:我真的只是在jq上扔东西,直到有东西粘在墙上...

# 1. in the shell, construct a JSON object string from the array => {"bbbb":1,"cccc":1}
printf -v jsonobj '{%s}' "$(printf '"%q":1\n' "${array[@]}" | paste -sd,)"

# 2. use that to test for non-membership in the jq select function
jq --argjson o "$jsonobj" '.foofoo.barbar |= map(select((.bar|in($o)) == false))' json.json

输出

{
  "foofoo": {
    "barbar": [
      {
        "foo": "0000",
        "bar": "aaaa"
      }
    ]
  }
}

您实际上没有显示所需的输出,所以我认为这就是您想要的。

答案 2 :(得分:0)

构造字典对象为有效的解决方案打开了一扇门。如果您的jq具有INDEX/2,则可以使用以下调用:

jq --arg p "${arr[*]}" '
  INDEX($p | split(" ")[]; .) as $dict
  | .foofoo.barbar 
      |= map(select($dict[.bar|tostring] | not))' 

如果您的jq没有INDEX/2,那么现在是升级的绝佳时机;否则,您可以通过谷歌搜索来破坏其定义: jq "def INDEX"