【问题标题】:Deleting multiple keys at once with jq使用 jq 一次删除多个键
【发布时间】:2016-07-13 15:22:37
【问题描述】:

我需要从一些 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"
  }
]

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

$ 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()) 指令?

【问题讨论】:

    标签: jq


    【解决方案1】:

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

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

    另外,考虑到,您可能更愿意将您想要的键列入白名单,而不是将特定键列入黑名单:

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

    【讨论】:

      【解决方案2】:

      没有必要同时使用mapdel

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

      这是一个使用“点式”路径表示法的解决方案:

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

      这是一个使用“数组样式”路径表示法的示例,它允许您将具有公共前缀的路径组合起来,如下所示:

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

      peak 的回答使用了mapdelpaths,不过您似乎也可以单独使用delpaths

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

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

      【讨论】:

        【解决方案3】:

        Louis 在其answer 中提到的“数组样式”和“点样式”表示法之间的更好折衷。

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

        jqplay


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

        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$"]

        【讨论】:

          【解决方案4】:

          除了@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

          【讨论】:

            【解决方案5】:

            delpaths 也是值得了解的,也许没有那么神秘:

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

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

            【讨论】:

            • delpaths 将设置为null 在提供的路径表达式中找到的键的值,它不会按照此处的要求删除键。
            • @LouisMaddox - 我已经使用 jq 1.3、1.4、1.5 和 1.6 测试了上面给出的程序,在所有情况下,结果都是删除了密钥。如果您对最近的投票负责,请不要忘记将其删除。谢谢。
            • 我仍然认为这是一个不受欢迎的答案:OP 表示“我正在尝试了解是否有比每次调用 map 和 del 更好的方法”。有:使用单个del 调用,这也将路径名周围的方括号数量减少到2,而不是8:jq 'del( .[] ["Country", "number", "Language"] )' test.json。您的答案有效,但我发现它是潜在的混淆来源和潜在的静默错误(因为 delpaths 不会删除密钥,而是在保留密钥时设置为 null)。这在过去一直困扰着我,所以我推荐使用更简单的del 来代替。
            • (a) 没有声称使用 delpaths 是最好的方法,只是说它是 Q 中要求的更好的方法。(b) 即使指向不存在的键的路径是包括在内,未添加密钥,因此我不理解您对“保留密钥”的担忧。
            • 我昨天刚被这个咬了一口,因此被否决了,就这么简单:-) 没有冒犯的意思。除非您编辑答案,否则 StackOverflow 不会让我取消投票。我对“保留密钥”的担忧是指在不使用 map 的情况下使用 delpaths,在这种情况下,它将将该密钥的值设置为 null,但保留密钥本身。
            猜你喜欢
            • 1970-01-01
            • 2018-03-07
            • 2019-10-30
            • 1970-01-01
            • 1970-01-01
            • 2017-03-14
            • 1970-01-01
            • 2020-09-17
            • 1970-01-01
            相关资源
            最近更新 更多