使用 jq 一次删除多个密钥

Deleting multiple keys at once with jq

提问人:antun 提问时间:3/26/2016 最后编辑:slmantun 更新时间:1/6/2022 访问量:56302

问:

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

测试.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"
  }
]

但是,我正在尝试了解是否有一种方法可以指定要删除的多个标签,因此我不必有多个指令?jqmap(del())

JQ公司

评论


答:

79赞 user3899165 3/26/2016 #1

您可以提供要删除的路径

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

此外,请考虑一下,您可能更愿意将所需的密钥列入白名单,而不是将特定密钥列入黑名单:

$ cat test.json | jq 'map({label, region, locale, currency})'
6赞 peak 3/26/2016 #2

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

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

由于参数 to 只是 JSON,因此这种方法对于编程删除特别有用,例如,如果键名称以 JSON 字符串形式提供。delpaths

评论

0赞 Louis Maddox 6/9/2020
delpaths将设置为在提供的路径表达式中找到的键的值,它不会删除键,如此处要求。null
0赞 peak 6/10/2020
@LouisMaddox - 我已经使用 jq 1.3、1.4、1.5 和 1.6 测试了上面给出的程序,在所有情况下,结果都是密钥被删除。如果您对最近的反对票负责,请不要忘记将其删除。谢谢。
0赞 Louis Maddox 6/10/2020
我仍然觉得这是一个不受欢迎的答案:OP 说“我正在努力学习是否有比每次都调用 map 和 del 更好的方法”。有:使用单个调用,这也会将路径名周围的方括号数量减少到 2 而不是 8:。您的答案有效,但我发现它可能是混淆和潜在静默错误的根源(因为不会以其他方式删除密钥,而是在保留密钥存在时设置为)。这在过去一直困扰着我,所以我建议改用更简单的电话。deljq 'del( .[] ["Country", "number", "Language"] )' test.jsondelpathsnulldel
2赞 peak 6/10/2020
(a) 没有声称使用 delpaths 是最好的方法,只是说它是 Q 中要求的更好方法。 (b) 即使包含指向不存在的密钥的路径,也不会添加密钥,因此我不理解您对“保留密钥存在”的担忧。
0赞 Louis Maddox 6/10/2020
我昨天刚刚被这个咬了一口,所以在此基础上投了反对票,真的就这么简单:-)不是故意冒犯的。StackOverflow 不会让我取消反对票,除非你编辑你的答案。我对“保留键存在”的担忧是指使用 without ,在这种情况下,它会将该键的值设置为 但保留键本身存在。delpathsmapnull
7赞 russholio 8/22/2019 #3

除了@user3899165的回答之外,我还发现要从“子对象”中删除键列表

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

评论

0赞 ALex_hha 7/27/2022
是否可以在不指定 a 和 а 的情况下删除所有内容?像这样的东西 ?d | ejq 'del(.*'["d", "e"])' example.json
0赞 ALex_hha 7/27/2022
有可能jq 'del(.[]["d", "e"])' example.json
30赞 Louis Maddox 6/10/2020 #4

没有必要同时使用 和 。mapdel

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

以下是使用“点式”路径表示法的解决方案:

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

下面是一个使用“数组样式”路径表示法的示例,它允许您将路径与通用前缀组合在一起,如下所示:

jq 'del( .[] ["Country", "number", "Language"] )' test.json
  • 将子路径组合在“最后一个共同祖先”(在本例中为顶级列表迭代器)下.[])

Peak 的答案使用了 和 ,尽管您似乎也可以单独使用它:mapdelpathsdelpaths

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

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

16赞 YenForYang 12/15/2020 #5

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)]

如果键包含特殊字符或以数字开头,则需要用双引号将其括起来,如下所示: 或 否则 。."foo$".["foo$"]

13赞 tquid 1/6/2022 #6

这个问题在谷歌结果中非常高,所以我想指出,在随后的几年中,显然已经发生了变化,因此您可以使用以下命令删除多个键:del

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

因此,不要试图弄清楚语法解决方法,假设您的 jq 版本是相当最新的。

评论

0赞 wolfyuk 4/21/2022
这是唯一对我有用的解决方案,没有出现错误jqCannot index string with string