return 如果其中包含的字典列表具有特定键或列表为空,则字典列表中的每个元素

return each element from a list-of-dictionaries if a list-of-dictionaries contained within has a specific key or list is empty

考虑到以下数据结构,我希望根据以下条件使用 jq return 每个文档:

  1. Return members 数组包含键 subPath
  2. 的所有文档
  3. Return members 数组不包含键 subPath
  4. 的所有文档
  5. Return members 数组为空的所有文档
[
  {
    "alternate_mode": "global-availability",
    "dynamic_ratio": "no",
    "enabled": "yes",
    "fallback_mode": "return-to-dns",
    "full_path": "/Common/a2ws-test.ree.se.net_pool",
    "load_balancing_mode": "global-availability",
    "manual_resume": "no",
    "max_answers_returned": 1,
    "members": [
      {
        "name": "a2ws-test.ree.se.net-443-vs",
        "partition": "Common",
        "subPath": "f5-tstltm-dmz-dc1-pair:/Common",
        "enabled": "yes",
        "limitMaxBps": 0,
        "limitMaxBpsStatus": "disabled",
        "limitMaxConnections": 0,
        "limitMaxConnectionsStatus": "disabled",
        "limitMaxPps": 0,
        "limitMaxPpsStatus": "disabled",
        "monitor": "default",
        "ratio": 1,
        "disabled": "no",
        "member_order": 0
      },
      {
        "name": "dc2-a2ws-test.ree.se.net-443-vs",
        "partition": "Common",
        "subPath": "f5-tstltm-dmz-dc2-pair:/Common",
        "enabled": "yes",
        "limitMaxBps": 0,
        "limitMaxBpsStatus": "disabled",
        "limitMaxConnections": 0,
        "limitMaxConnectionsStatus": "disabled",
        "limitMaxPps": 0,
        "limitMaxPpsStatus": "disabled",
        "monitor": "default",
        "ratio": 1,
        "disabled": "no",
        "member_order": 1
      }
    ],
    "name": "a2ws-test.ree.se.net_pool",
    "partition": "Common",
    "qos_hit_ratio": 5,
    "qos_hops": 0,
    "qos_kilobytes_second": 3,
    "qos_lcs": 30,
    "qos_packet_rate": 1,
    "qos_rtt": 50,
    "qos_topology": 0,
    "qos_vs_capacity": 0,
    "qos_vs_score": 0,
    "ttl": 30,
    "verify_member_availability": "yes"
  },
  {
    "alternate_mode": "round-robin",
    "dynamic_ratio": "no",
    "enabled": "yes",
    "fallback_mode": "return-to-dns",
    "full_path": "/Common/aci-apic.ree.se.net_pool",
    "load_balancing_mode": "round-robin",
    "manual_resume": "no",
    "max_answers_returned": 1,
    "members": [
      {
        "name": "prd_dc1_servers:aci-apic01.ree.se.net",
        "partition": "Common",
        "enabled": "yes",
        "limitMaxBps": 0,
        "limitMaxBpsStatus": "disabled",
        "limitMaxConnections": 0,
        "limitMaxConnectionsStatus": "disabled",
        "limitMaxPps": 0,
        "limitMaxPpsStatus": "disabled",
        "monitor": "default",
        "ratio": 1,
        "disabled": "no",
        "member_order": 0
      },
      {
        "name": "prd_dc1_servers:aci-apic02.ree.se.net",
        "partition": "Common",
        "enabled": "yes",
        "limitMaxBps": 0,
        "limitMaxBpsStatus": "disabled",
        "limitMaxConnections": 0,
        "limitMaxConnectionsStatus": "disabled",
        "limitMaxPps": 0,
        "limitMaxPpsStatus": "disabled",
        "monitor": "default",
        "ratio": 1,
        "disabled": "no",
        "member_order": 1
      },
      {
        "name": "prd_dc2_servers:aci-apic03.ree.se.net",
        "partition": "Common",
        "enabled": "yes",
        "limitMaxBps": 0,
        "limitMaxBpsStatus": "disabled",
        "limitMaxConnections": 0,
        "limitMaxConnectionsStatus": "disabled",
        "limitMaxPps": 0,
        "limitMaxPpsStatus": "disabled",
        "monitor": "default",
        "ratio": 1,
        "disabled": "no",
        "member_order": 2
      }
    ],
    "name": "aci-apic.ree.se.net_pool",
    "partition": "Common",
    "qos_hit_ratio": 5,
    "qos_hops": 0,
    "qos_kilobytes_second": 3,
    "qos_lcs": 30,
    "qos_packet_rate": 1,
    "qos_rtt": 50,
    "qos_topology": 0,
    "qos_vs_capacity": 0,
    "qos_vs_score": 0,
    "ttl": 30,
    "verify_member_availability": "yes"
  },
  {
    "alternate_mode": "global-availability",
    "dynamic_ratio": "no",
    "enabled": "yes",
    "fallback_mode": "return-to-dns",
    "full_path": "/Common/b2b.ree.se.net_pool",
    "load_balancing_mode": "global-availability",
    "manual_resume": "no",
    "max_answers_returned": 1,
    "members": [],
    "name": "b2b.ree.se.net_pool",
    "partition": "Common",
    "qos_hit_ratio": 5,
    "qos_hops": 0,
    "qos_kilobytes_second": 3,
    "qos_lcs": 30,
    "qos_packet_rate": 1,
    "qos_rtt": 50,
    "qos_topology": 0,
    "qos_vs_capacity": 0,
    "qos_vs_score": 0,
    "ttl": 30,
    "verify_member_availability": "yes"
  }
]

为简洁起见,我选择了 name 键来演示 returned 是什么。请注意,当我想要的是单个文档时,return为 #1 和 #2 编辑了倍数/重复项。

对于#1:

 ➜  jq -r '.[] | select(.members[] | has("subPath")).name' test.json 
a2ws-test.ree.se.net_pool
a2ws-test.ree.se.net_pool

对于#2:

 ➜  jq -r '.[] | select(.members[] | has("subPath") | not).name' test.json    
aci-apic.ree.se.net_pool
aci-apic.ree.se.net_pool
aci-apic.ree.se.net_pool

对于#3:

 ➜  jq -r '.[] | select(.members[] | length == 0)' test.json
 ➜  

最后,我想像前面提到的那样查询这个 json,并从中创建 yaml 输出,例如:

echo "# Discovered Members"
## Discovered Members have the key "subPath"
## look for and only return those json documents
cat test.json | jq -r '.[] | select(.members[] | has("subPath")) |
      "- name: " + .name,
      "  state: " + .enabled,
      "  type: a",
      "  preferred_lb_method: " + .load_balancing_mode,
      "  alternate_lb_method: " + .alternate_mode,
      "  fallback_lb_method: " + .fallback_mode,
      "  max_answers_returned: " + (.max_answers_returned | tostring),
      "  ttl: " + (.ttl | tostring),
      "  members:", (.members[] |
      "    - server: " + (.subPath | split(":") | first),
      "      virtual_server: /Common/" + .name,
      "      state: " + .enabled,
      "      member_order: " + (.member_order | tostring),
      "      ratio: " + (.ratio | tostring),
      "      monitor: " + .monitor)' \
    | sed 's/state: yes/state: present/g' \
    | sed 's/state: no/state: disabled/g'

echo "# Static Members"
# Static Members DO NOT have the key "subPath"
# look for and only return those json documents
jq -r '.[] | select(.members[] | has("subPath") | not) |
      "- name: " + .name,
      "  state: " + .enabled,
      "  type: a",
      "  preferred_lb_method: " + .load_balancing_mode,
      "  alternate_lb_method: " + .alternate_mode,
      "  fallback_lb_method: " + .fallback_mode,
      "  max_answers_returned: " + (.max_answers_returned | tostring),
      "  ttl: " + (.ttl | tostring),
      "  members:", (.members[] |
      "    - server: " + (.name | split(":") | first),
      "      virtual_server: " + (.name | split(":") | last),
      "      state: " + .enabled,
      "      member_order: " + (.member_order | tostring),
      "      ratio: " + (.ratio | tostring),
      "      monitor: " + .monitor)' test.json \
    | sed 's/dev_dc1_servers/static-f5-dev-dc1-servers/g' \
    | sed 's/dev_dc2_servers/static-f5-dev-dc2-servers/g' \
    | sed 's/tst_dc1_servers/static-f5-tst-dc1-servers/g' \
    | sed 's/tst_dc2_servers/static-f5-tst-dc2-servers/g' \
    | sed 's/prd_dc1_servers/static-f5-prd-dc1-servers/g' \
    | sed 's/prd_dc2_servers/static-f5-prd-dc2-servers/g' \
    | sed 's/state: yes/state: present/g' \
    | sed 's/state: no/state: disabled/g'

# those that do not have members defined, but still need to be represented as objects to consider
# figure out the jq first

我尝试通过管道连接到 unique 但没有成功,这表明我的查询不正确。

我将如何根据每个词典中包含的列表是否包含特定键名来 return 从词典列表中搜索每个文档,并找到列表是空的?

对于#1 和#2,我不清楚你是想要第一个满足条件的项目,还是满足条件的不同项目的集合。

对于第一项,您可以使用 first:

first(.[] | select(.members[] | has("subPath")).name)

对于不同的项目,您当然可以使用 unique:

map(select(.members[] | has("subPath")).name ) | unique[]

与#2 类似。

对于 #3,您需要检查 .members|length,而不是 .members|length:

.[] | select(.members | length == 0)