【问题标题】:How to conditionally map values to new object with jq如何使用 jq 有条件地将值映射到新对象
【发布时间】:2018-02-13 09:05:51
【问题描述】:

我正在从 DigitalOcean JSON API 获取液滴列表,并使用 jq map 将响应转换为我需要的信息。

我希望能够根据响应是否包含具有特定值的键,向我的新对象添加一个可选的键值对。

使用select() 时,如果响应不包含匹配项,则会从我的新对象中删除整个液滴条目,而不仅仅是键。

如何过滤单个键而不是整个条目?

详细说明:

单个液滴的响应如下所示:

 "id": 12345678,
 "name": "my-droplet",
 ...
 "networks": {
      "v4": [
        {
          "ip_address": "123.456.78.90",
          "netmask": "255.255.240.0",
          "gateway": "123.123.0.1",
          "type": "public"
        },
        {
          "ip_address": "10.123.45.67",
          "netmask": "255.255.0.0",
          "gateway": "10.123.0.1",
          "type": "private"
        }
      ],
      "v6": []
    },
 ...

我想把它转换成一个形式的对象:

{
  "id": 12345678,
  "name": "my-droplet",
  "public_ip": "123.456.78.90",
  "private_ip" "10.123.45.67"
} 

所有 Droplet 都有一个公共 IP,但私有 IP 是可选的。

我有这个,它忽略了可选的私有 IP,到目前为止工作正常:

jq '.droplets | map({id: .id, name: .name, status: .status, public_ip: .networks.v4[] | select(.type=="public") | .ip_address})'

但是,一旦我添加了私有 IP,响应中会丢失任何没有的 droplet:

jq '.droplets | map({id: .id, name: .name, status: .status, public_ip: .networks.v4[] | select(.type=="public") | .ip_address, private_ip: .networks.v4[] | select(.type=="private") | .ip_address})'

我想我需要以某种方式使用连接或条件,但我不太清楚语法。

注意:我发现了这个类似的问题,但它不包括更改密钥的名称:denormalizing JSON with jq

【问题讨论】:

  • 为了清楚起见:如果没有私有 IP,那么理想情况下,密钥将不存在。我没有多个私有 IP 的情况。

标签: json jq


【解决方案1】:

当没有私有 ip(或者确实有多个)时,您没有准确说明应该发生什么,但以下内容应该可以帮助您。

.droplets
| map({id, name, status, 
       public_ip: (first(.networks.v4[] | select(.type=="public"))  // {})
                  | .ip_address,
       private_ip: (first(.networks.v4[] | select(.type=="private")) // {})
                  | .ip_address } )

条件键

def one(condition): first(.[] | select(condition)) // null;

.droplets
| map({id, name, status}
      + (.networks.v4
         | { public_ip: one(.type=="public") | .ip_address}
           + (one(.type=="private") 
              | if . then {private_ip: .ip_address} else null end ) ))

【讨论】:

  • 我添加了一条评论,以澄清我在理想情况下希望只添加存在的密钥 - 但空值也可以。谢谢!
  • 您对// {} 语法有任何参考吗?我详细搜索了 jq 手册,寻找某种默认概念。
  • 为了避免空值,您可以使用if then else end,或者如果它为空值则删除该键。 // 简要记录在手册中,更全面地在 jq FAQ github.com/stedolan/jq/wiki/FAQ
  • 我在 jqplay 中测试了这个解决方案,它似乎扩展了公共 IP 和私有 IP 的所有可能组合:jqplay.org/s/7ZvdfPwZ-G
  • 更正括号,并添加 first()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
相关资源
最近更新 更多