使用 jq 一次删除多个键

Deleting multiple keys at once with jq

我需要一次从一些 JSON 中删除多个键(使用 jq),我正在尝试了解是否有比调用 map 和每次都删除。这是我的输入数据:

test.json

[
  {
    "label": "US : USA : English",
    "Country": "USA",
    "region": "US",
    "Language": "English",
    "locale": "en",
    "currency": "USD",
    "number": "USD"
  },
  {
    "label": "AU : Australia : English",
    "Country": "Australia",
    "region": "AU",
    "Language": "English",
    "locale": "en",
    "currency": "AUD",
    "number": "AUD"
  },
  {
    "label": "CA : Canada : English",
    "Country": "Canada",
    "region": "CA",
    "Language": "English",
    "locale": "en",
    "currency": "CAD",
    "number": "CAD"
  }
]

对于每个项目,我想删除数字、语言和国家/地区键。我可以用这个命令来做到这一点:

$ cat test.json | jq 'map(del(.Country)) | map(del(.number)) | map(del(.Language))'

效果很好,我得到了想要的输出:

[
  {
    "label": "US : USA : English",
    "region": "US",
    "locale": "en",
    "currency": "USD"
  },
  {
    "label": "AU : Australia : English",
    "region": "AU",
    "locale": "en",
    "currency": "AUD"
  },
  {
    "label": "CA : Canada : English",
    "region": "CA",
    "locale": "en",
    "currency": "CAD"
  }
]

但是,我想了解是否有一种 jq 方法可以指定要删除的多个标签,这样我就不必有多个 map(del()) 指令?

您可以提供 要删除的路径:

$ cat test.json | jq 'map(del(.Country, .number, .Language))'

另外,考虑一下,您可能更愿意将您确实想要的密钥列入白名单,而不是将特定密钥列入黑名单:

$ cat test.json | jq 'map({label, region, locale, currency})'

delpaths 也值得了解,也许不那么神秘:

map( delpaths( [["Country"], ["number"], ["Language"]] ))

由于 delpaths 的参数只是 JSON,这种方法对于编程删除特别有用,例如如果键名可用作 JSON 字符串。

除了@user3899165 的回答,我发现要从 "sub-object"

中删除一个键列表
example.json

{
    "a": {
        "b": "hello",
        "c": "world",
        "d": "here's",
        "e": "the"
    },
    "f": {
        "g": "song",
        "h": "that",
        "i": "I'm",
        "j": "singing"
    }
}

$ jq 'del(.a["d", "e"])' example.json

不需要同时使用mapdel

您可以将多个路径传递给 del,以逗号分隔。

这是一个使用 "dot-style" 路径符号的解决方案:

jq 'del( .[] .Country, .[] .number, .[] .Language )' test.json
  • 不需要引号(您可能觉得这样更易读)
  • 不对路径进行分组(要求您为每个路径重新输入一次 .[]

这是一个使用 "array-style" 路径表示法的示例,它允许您将路径与通用前缀组合在一起,如下所示:

jq 'del( .[] ["Country", "number", "Language"] )' test.json
  • 合并 "last-common ancestor" 下的子路径(在本例中是顶级列表迭代器 .[]

peak 的答案使用了 mapdelpaths,尽管您似乎也可以单独使用 delpaths

jq '[.[] | delpaths( [["Country"], ["number"], ["Language"]] )]' test.json
  • 需要引号和单例数组
  • 需要您将其放回列表中(带开始和结束方括号)

总的来说,为了简洁起见,我会在这里使用数组样式的表示法,但是知道做同一件事的多种方法总是好的。

Louis 在他的 .

中提到的“数组式”和“点式”符号之间的更好折衷
del(.[] | .Country, .number, .Language)

jqplay


此表单还可用于从嵌套对象中删除键列表(请参阅 russholio 的 ):

del(.a | .d, .e)

暗示您也可以选择一个索引来从以下位置删除键:

del(.[1] | .Country, .number, .Language)

或多个:

del(.[2,3,4] | .Country,.number,.Language)

您可以使用 range() 函数删除范围(切片符号不起作用):

del(.[range(2;5)] | .Country,.number,.Language)  # same as targetting indices 2,3,4

一些旁注:

map(del(.Country,.number,.Language))
# Is by definition equivalent to
[.[] | del(.Country,.number,.Language)]

If the key contains special characters or starts with a digit, you need to surround it with double quotes like this: ."foo$", or else .["foo$"].

这个问题在 google 结果中的排名很高,所以我想指出,在这几年中的某个时候,del 显然已被更改,以便您可以删除多个密钥只有:

del(.key1, .key2, ...)

因此,假设您的 jq 版本是合理的最新版本,请不要为找出语法变通办法而费尽心思。