jq:根据对象值条件递归删除对象的最简单方法

mwa*_*wag 7 json jq

我想用来jq删除 JSON“对象”中的所有字典(我通常使用该术语来指代数组或字典)

a) 包含名为“delete_me”的键,并且 b) 其中键“delete_me”满足某些预定条件(空、非零、真等)

基本上,我想要实现的逻辑是:遍历输入,在每个节点上,如果该节点不是数组或对象,则保留它并继续,否则,保留它但从中删除任何属于字典的子节点条件 a) 或 b) 失败。

有什么建议么?

输入示例:

{
  "a": { "foo": "bar" },
  "b": {
    "i": {
      "A": {
        "i": [
          {
            "foo": {},
            "bar": {
              "delete_if_this_is_null": false,
              "an_array": [],
              "another_array": [
                {
                    "delete_if_this_is_null": null,
                    "foo": "bar"
                }
              ],
              "etc": ""
            },
            "foo2": "s"
          },
          {
            "foo": {
              "an_array": [
                {
                  "delete_if_this_is_null": "ok",
                  "foo":"bar",
                  "another_object": { "a":1 }
                },
                {
                  "delete_if_this_is_null": null,
                  "foo2":"bar2",
                  "another_object": { "a":1 },
                  "name": null
                }
              ],
              "an_object": {
                "delete_if_this_is_null":null,
                "foo3":"bar3"
              }
            },
            "zero": 0,
            "b": "b"
          }
        ]
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

如果“delete_me”键是delete_if_this_is_null并且预定条件是delete_if_this_is_null == null

{
  "a": { "foo": "bar" },
  "b": {
    "i": {
      "A": {
        "i": [
          {
            "foo": {},
            "bar": {
              "delete_if_this_is_null": false,
              "an_array": [],
              "another_array": [],
              "etc": ""
            },
            "foo2": "s"
          },
          {
            "foo": {
              "an_array": [
                {
                  "delete_if_this_is_null": "ok",
                  "foo":"bar",
                  "another_object": { "a":1 }
                }
              ]
            },
            "zero": 0,
            "b": "b"
          }
        ]
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


更新:这是解决方案:假设输入位于文件“input.json”中:

jq 'def walk(f):
  . as $in
  | if type == "object" then
      reduce keys[] as $key
        ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
  elif type == "array" then map( walk(f) ) | f
  else f
  end;

def mapper(f):
  if type == "array" then map(f)
  elif type == "object" then
  . as $in
  | reduce keys[] as $key
      ({};
       [$in[$key] | f ] as $value
       | if $value | length == 0 then .
         else . + {($key): $value[0]} end)
  else .
  end;

walk( mapper(select((type == "object" and .delete_if_this_is_null == null) | not)) )' < input.json
Run Code Online (Sandbox Code Playgroud)

pea*_*eak 6

杰夫的解决方案可能会带来太多影响。例如,使用:

def data: [1,2, {"hello": {"delete_me": true, "a":3 }, "there": 4} ]; ];
Run Code Online (Sandbox Code Playgroud)

杰夫的解决方案产生空(即什么也没有)。

因此,以下内容可能更接近您正在寻找的内容:

walk(if (type == "object" and .delete_me) then del(.) else . end )
Run Code Online (Sandbox Code Playgroud)

对于data,这会产生:

[1,2,{"hello":null,"there":4}]
Run Code Online (Sandbox Code Playgroud)

替代解决方案

如果需要一个消除上例中的解决方案"hello":null,则需要 jq 的 map_values/1 的变体。这是一种方法:

def mapper(f):
  if type == "array" then map(f)
  elif type == "object" then
  . as $in
  | reduce keys[] as $key
      ({};
       [$in[$key] | f ] as $value
       | if $value | length == 0 then . 
         else . + {($key): $value[0]} end)
  else .
  end;

data | walk( mapper(select((type == "object" and .delete_me) | not)) )
Run Code Online (Sandbox Code Playgroud)

结果是:

[1,2,{"there":4}]
Run Code Online (Sandbox Code Playgroud)