簡體   English   中英

jq:基於對象值條件遞歸刪除對象的最簡單方法

[英]jq: easiest way to recursively remove objects based on object value condition

我想使用jq刪除JSON“對象”(我通常使用該術語指代數組或字典)中的所有字典

a)包含一個名為“ delete_me”的鍵,並且b)其中鍵“ delete_me”滿足某些預定條件(null,非零,true等)

基本上,我要實現的邏輯是:遍歷輸入,然后在每個節點上,如果該節點不是數組或對象,則繼續輸入並繼續前進,否則,保留它,但從中刪除任何字典的子級條件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"
          }
        ]
      }
    }
  }
}

如果“ 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"
          }
        ]
      }
    }
  }
}


更新:這是解決方案:假設輸入位於文件“ 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 

這是使用遞歸函數的解決方案:

def clean(condition):
  if type == "object" then
    if condition
    then empty
    else
    with_entries(
      if (.value|type) == "object" and (.value|condition)
      then empty
      else .value |= clean(condition)
      end
    )
    end
  elif type == "array" then
    map(
      if type == "object" and condition
      then empty
      else clean(condition)
      end
    )
  else .
  end
;

clean(
  has("delete_if_this_is_null") and (.delete_if_this_is_null == null)
)

我不確定您要在問題中完成什么,但是我假設您要遞歸搜索json響應並刪除滿足某些條件的json對象。

您可以使用的幫助做到這一點比較容易walk過濾器將在JQ的未來版本中來了,看到在實施

# Apply f to composite entities recursively, and to atoms
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 filter_objects(predicate): # removes objects that satisfies some predicate
    walk(
        if (type == "object") and (predicate) then
            empty
        else
            .
        end
    )
    ;
filter_objects(.delete_me) # remove objects that has a truthy property "delete_me"

傑夫的解決方案可能會改變得太多。 例如,使用:

def data: [1,2, {"hello": {"delete_me": true, "a":3 }, "there": 4} ]; ];

傑夫的解決方案得出的結果是空的(即什么也沒有)。

因此,以下內容可能更接近您要尋找的內容:

walk(if (type == "object" and .delete_me) then del(.) else . end )

對於data ,得出:

[1,2,{"hello":null,"there":4}]

替代解決方案

如果需要在上面的示例中消除"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)) )

結果是:

[1,2,{"there":4}]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM