使用jq一次删除多个键

ant*_*tun 11 jq

我需要从一些JSON(使用jq)一次删除多个键,并且我试图了解是否有更好的方法来执行此操作,而不是每次都调用map和del.这是我的输入数据:

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"
  }
]
Run Code Online (Sandbox Code Playgroud)

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

$ cat test.json | jq 'map(del(.Country)) | map(del(.number)) | map(del(.Language))'
Run Code Online (Sandbox Code Playgroud)

这很好,我得到了所需的输出:

[
  {
    "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"
  }
]
Run Code Online (Sandbox Code Playgroud)

但是,我试图了解是否有jq方式指定要删除的多个标签,所以我不必有多个jq指令?

在此先感谢您的帮助!

小智 19

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

$ cat test.json | jq 'map(del(.Country, .number, .Language))'
Run Code Online (Sandbox Code Playgroud)

另外,请注意,您可能更愿意将您想要的密钥列入白名单,而不是将特定密钥列入黑名单:

$ cat test.json | jq 'map({label, region, locale, currency})'
Run Code Online (Sandbox Code Playgroud)


小智 13

这个问题在谷歌结果中的排名非常高,所以我想指出,在接下来的几年中,这个问题del显然已经被改变,这样你就可以删除多个键:

del(.key1, .key2, ...)
Run Code Online (Sandbox Code Playgroud)

因此,假设您的 jq 版本相当最新,就不要费尽心思去寻找语法解决方法。


Lou*_*dox 12

没有必要同时使用mapdel

You can pass multiple paths to del, separated by commas.

Here is a solution using "dot-style" path notation:

jq 'del( .[] .Country, .[] .number, .[] .Language )' test.json
Run Code Online (Sandbox Code Playgroud)
  • doesn't require quotation marks (which you may feel makes it more readable)
  • doesn't group the paths (requires you to retype .[] once per path)

Here is an example using "array-style" path notation, which allows you to combine paths with a common prefix like so:

jq 'del( .[] ["Country", "number", "Language"] )' test.json
Run Code Online (Sandbox Code Playgroud)
  • Combines subpaths under the "last-common ancestor" (which in this case is the top-level list iterator .[])

peak's answer uses map and delpaths, though it seems you can also use delpaths on its own:

jq '[.[] | delpaths( [["Country"], ["number"], ["Language"]] )]' test.json
Run Code Online (Sandbox Code Playgroud)
  • Requires both quotation marks and array of singleton arrays
  • Requires you to put it back into a list (with the start and end square brackets)

Overall, here I'd go for the array-style notation for brevity, but it's always good to know multiple ways to do the same thing.


Yen*_*ang 8

路易斯在他的回答中提到的“数组样式”和“点样式”符号之间更好的折衷。

del(.[] | .Country, .number, .Language)
Run Code Online (Sandbox Code Playgroud)

jqplay


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

del(.a | .d, .e)
Run Code Online (Sandbox Code Playgroud)

这意味着您还可以选择单个索引来从以下位置删除键:

del(.[1] | .Country, .number, .Language)
Run Code Online (Sandbox Code Playgroud)

或多个:

del(.[2,3,4] | .Country,.number,.Language)
Run Code Online (Sandbox Code Playgroud)

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

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

一些旁注:

map(del(.Country,.number,.Language))
# Is by definition equivalent to
[.[] | del(.Country,.number,.Language)]
Run Code Online (Sandbox Code Playgroud)

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


pea*_*eak 6

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

map( delpaths( [["Country"], ["number"], ["Language"]] ))
Run Code Online (Sandbox Code Playgroud)

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

  • (a) 没有人声称使用 delpaths 是最好的方法,只是它是 Q 中所要求的更好的方法。 (b) 即使包含到不存在的密钥的路径,也不会添加该密钥,所以我不明白你对“留下钥匙”的担忧。 (2认同)

rus*_*lio 6

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

example.json

{
    "a": {
        "b": "hello",
        "c": "world",
        "d": "here's",
        "e": "the"
    },
    "f": {
        "g": "song",
        "h": "that",
        "i": "I'm",
        "j": "singing"
    }
}
Run Code Online (Sandbox Code Playgroud)

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