【问题标题】:Convert json to csv with only selected keys仅使用选定的键将 json 转换为 csv
【发布时间】:2021-02-04 16:49:19
【问题描述】:

我有一个json脚本,内容如下。

{
  "syncToken": "1612442658",
  "createDate": "2021-02-04-12-44-18",
  "prefixes": [
    {
      "ip_prefix": "3.5.140.0/22",
      "region": "ap-northeast-2",
      "service": "AMAZON",
      "network_border_group": "ap-northeast-2"
    },
    {
      "ip_prefix": "35.180.0.0/16",
      "region": "eu-west-3",
      "service": "AMAZON",
      "network_border_group": "eu-west-3"
    },
    {
      "ip_prefix": "52.93.178.234/32",
      "region": "us-west-1",
      "service": "AMAZON",
      "network_border_group": "us-west-1"
    }
  ]
}

我的要求是将此 json 转换为以下格式的 csv。

ip_prefix         region           service    
3.5.140.0/22      ap-northeast-2   AMAZON     
35.180.0.0/16     eu-west-3        AMAZON     
52.93.178.234/32  us-west-1        AMAZON   

使用 jq 使用以下命令转换数据

jq -r '(.prefixes[0] | keys_unsorted), (.prefixes[] | to_entries | map(.value))|@tsv' ip-ranges.json 

但它会导出所有密钥。在导出多个键中的几个键时需要帮助。

【问题讨论】:

  • 请指定如何指定所需的键 - 显式(作为白名单)还是隐式(通过黑名单)?在jq程序中,还是作为调用jq时的参数,还是其他方式?
  • 我希望在执行 jq 命令时将密钥作为参数传递。类似下面的 jq -r "desired keys" "key values" @tsv。 file.json 在上述情况下,我希望在 json 文件转换为 csv 时排除键“network_border_group”。
  • 终于找到了解决上述问题的办法。我使用以下命令摆脱了我不想要的密钥。 jq 'del(.prefixes[].network_border_group)' | jq -r '(.prefixes[0] | keys_unsorted), (.prefixes[] | to_entries | map(.value))|@tsv' 非常感谢我可以使用的任何其他解决方案。

标签: json shell export-to-csv jq


【解决方案1】:

假设您在$fields 中有一个字段列表。那么你只需要这个:

.prefixes |                 // The array of records from which we will build our rows.
(
   $fields,                 // The header row
   (                        // The data rows
      .[] |                 //   For each input,
      [ .[ $fields[] ] ]    //   create an array of the selected values
   )
) |
@tsv

这将作为以下所有解决方案的基础。不同的是我们如何构建$fields


允许列表:

[ "ip_prefix", "region", "service" ] as $fields |
.prefixes |
( $fields, ( .[] | [ .[ $fields[] ] ] ) ) | @tsv

使用示例:

jq -r --argjson fields '[ "ip_prefix", "region", "service" ]' '
   [ "ip_prefix", "region", "service" ] as $fields |
   .prefixes |
   ( $fields, ( .[] | [ .[ $fields[] ] ] ) ) | @tsv
' data.json

被阻止的项目:

.prefixes |
( .[0] | keys_unsorted | map(select( . != "network_border_group" )) ) as $fields |
.prefixes |
( $fields, ( .[] | [ .[ $fields[] ] ] ) ) | @tsv

阻止列表:

[ "network_border_group" ] as $blocked |
.prefixes |
( .[0] | keys_unsorted - $blocked ) as $fields |
( $fields, ( .[] | [ .[ $fields[] ] ] ) ) | @tsv

使用示例:

jq -r --argjson blocked '[ "network_border_group" ]' '
   .prefixes |
   ( .[0] | keys_unsorted - $blocked ) as $fields |
   ( $fields, ( .[] | [ .[ $fields[] ] ] ) ) | @tsv
' data.json

【讨论】:

  • @peak,我希望你能这么说:) 已修复。干净多了!
【解决方案2】:

以下变体假定“白名单”方法是合适的:

没有标题行

.prefixes[] | [.ip_prefix,.region,.service] | @csv

或者,将白名单指定为参数:

jq -r --argjson whitelist '["ip_prefix","region","service"]' '
  .prefixes[] | [ .[$whitelist[]] ] | @csv'

带有标题行:

["ip_prefix","region","service"] as $whitelist
| $whitelist,
  (.prefixes[] | [getpath($whitelist[]|[.])])
| @csv

等等

请注意,以上都不需要对源中的对象中的键进行任何特殊排序。

【讨论】:

    【解决方案3】:

    一种方法是使用update operator |= 删除不需要的键值对。

    jq -r '.prefixes[] |= del(.network_border_group)
           | (.prefixes[0] | keys_unsorted),
             (.prefixes[] | to_entries | map(.value))
           | @tsv'
    

    【讨论】:

    • .prefixes[] |= del(.network_border_group)可以简化为del(.prefixes[].network_border_group)
    • 当你只使用前导 .prefixes | 时,没有理由将 .prefixes 重复三次
    • 请注意,这假定对象内键的顺序一致。
    猜你喜欢
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 2020-10-26
    相关资源
    最近更新 更多