首页 > 解决方案 > JQ:删除不必要的键并重新格式化 JSON - 最有效的方法

问题描述

我有两个问题要问。这是下面的 JSON 文件。

[
    {
        "Header": {
            "Region": "DC1"
        },
        "Body": [
            {
                "agentMetaInfoDtos": [],
                "avgTraffic": 682,
                "minAgentVersion": "1.191.0.20180101-000000",
                "standardAgentVersion": null,
                "tenantState": "ACTIVE",
                "tenantUuid": "DC1-Tenant1"
            },
            {
                "agentMetaInfoDtos": [],
                "avgTraffic": 957,
                "minAgentVersion": "1.185.0.20180101-000000",
                "standardAgentVersion": null,
                "tenantState": "DISABLED",
                "tenantUuid": "DC1-Tenant2"
            }
        ]
    },
    {
        "Header": {
            "Region": "DC2"
        },
        "Body": [
            {
                "agentMetaInfoDtos": [],
                "avgTraffic": 690,
                "minAgentVersion": "1.163.0.20180101-000000",
                "standardAgentVersion": null,
                "tenantState": "ACTIVE",
                "tenantUuid": "DC2-t4-p1"
            },
            {
                "agentMetaInfoDtos": [],
                "avgTraffic": 2441,
                "minAgentVersion": "1.161.0.20180101-000000",
                "standardAgentVersion": null,
                "tenantState": "ACTIVE",
                "tenantUuid": "DC2-t5-p2"
            }
        ]
    },
    {
        "Header": {
            "Region": "DC3"
        },
        "Body": [
            {
                "agentMetaInfoDtos": [],
                "avgTraffic": 2046,
                "minAgentVersion": "1.169.0.20180101-000000",
                "standardAgentVersion": null,
                "tenantState": "ACTIVE",
                "tenantUuid": "DC3-r1-p1"
            },
            {
                "agentMetaInfoDtos": [],
                "avgTraffic": 0,
                "minAgentVersion": null,
                "standardAgentVersion": null,
                "tenantState": "FORSAKEN",
                "tenantUuid": "DC3-r2-d1"
            }
        ]
    }
]

首先,我想删除不必要的键并重新格式化 JSON。我想让结果如下所示

[
  {
    "Region": "DC1",
    "Tenants": [
      {
        "tenantState": "ACTIVE",
        "tenantUuid": "DC1-Tenant1"
      },
      {
        "tenantState": "DISABLED",
        "tenantUuid": "DC1-Tenant2"
      }
    ]
  },
  {
    "Region": "DC2",
    "Tenants": [
      {
        "tenantState": "ACTIVE",
        "tenantUuid": "DC2-t4-p1"
      },
      {
        "tenantState": "ACTIVE",
        "tenantUuid": "DC2-t5-p2"
      }
    ]
  },
  {
    "Region": "DC3",
    "Tenants": [
      {
        "tenantState": "ACTIVE",
        "tenantUuid": "DC3-r1-p1"
      },
      {
        "tenantState": "FORSAKEN",
        "tenantUuid": "DC3-r2-d1"
      }
    ]
  }
]

我的蛮力(假设是哑)过滤器如下 - 删除不需要的所有内容(顺便说一句,下面只是我需要删除的键的子集,还有更多):

del (.[].Body[].agentMetaInfoDtos) | del (.[].Body[].avgTraffic)  | del (.[].Body[].minAgentVersion) | del (.[].Body[].standardAgentVersion) | del (.[].Body[].serverDistribution)  |  [.[] | {"Region": .Header.Region, Tenants:[ .Body[]] } ]

但是应该有更好的方法来做到这一点 - 只选择需要的东西而不是删除其他所有东西。顺便说一句,在该Body[]部分中它始终是相同数量的键,它是内容agentMetaInfoDtos[]和其他不同的数组/键。tenantState可以有五个不同的值。

首先,尝试使用以下过滤器尝试选择正确的键,而不是删除其他所有内容:

[.[] | {Region: .Header.Region, Tenants:[ {tenantUuid: .Body[].tenantUuid, tenantState: .Body[].tenantState} ] }] 

但结果是键/值的重复,如下所示。

我确信有多种方法可以实现我想要的,有人可以提供速成课程或至少指出正确的方向吗?

[
  {
    "Region": "DC1",
    "Tenants": [
      {
        "tenantUuid": "DC1-Tenant1",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC1-Tenant1",
        "tenantState": "DISABLED"
      },
      {
        "tenantUuid": "DC1-Tenant2",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC1-Tenant2",
        "tenantState": "DISABLED"
      }
    ]
  },
  {
    "Region": "DC2",
    "Tenants": [
      {
        "tenantUuid": "DC2-t4-p1",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC2-t4-p1",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC2-t5-p2",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC2-t5-p2",
        "tenantState": "ACTIVE"
      }
    ]
  },
  {
    "Region": "DC3",
    "Tenants": [
      {
        "tenantUuid": "DC3-r1-p1",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC3-r1-p1",
        "tenantState": "FORSAKEN"
      },
      {
        "tenantUuid": "DC3-r2-d1",
        "tenantState": "ACTIVE"
      },
      {
        "tenantUuid": "DC3-r2-d1",
        "tenantState": "FORSAKEN"
      }
    ]
  }
]

第二个问题 - 即使我得到了结果,之后我想进一步过滤掉它,只保留状态为 DISABLED 的条目。所以我使用了过滤器 map(select (.Tenants[].tenantState == "DISABLED" )),但结果显示 DC3 中的活动和禁用租户,如下所示。

有什么提示我在这里做错了吗?

[
  {
    "Region": "DC1",
    "Tenants": [
      {
        "tenantState": "ACTIVE",
        "tenantUuid": "DC1-Tenant1"
      },
      {
        "tenantState": "DISABLED",
        "tenantUuid": "DC1-Tenant2"
      }
    ]
  }
]

标签: arraysjsonsortingjq

解决方案


第1部分

只需展开 .Body 一次即可轻松回答问题的第一部分:

[.[] | {Region: .Header.Region, Tenants: [.Body[] | {tenantUuid, tenantState}] }]

第2部分

为了简化这里的说明,让我们过滤上面得到的结果。如果我们想修改 .Tenants 以仅包含具有 .tenantState == "DISABLED" 的对象,我们可以将以下过滤器添加到管道中:

map( .Tenants |= map(select(.tenantState == "DISABLED")) )

然而,Q 建议应该从最终结果中排除空数组,因此我们可以进一步补充:

map( select(.Tenants != []) )

总之

综上所述:

[.[] | {Region: .Header.Region, Tenants: [.Body[] | {tenantUuid, tenantState}] }]
| map( .Tenants |= map(select(.tenantState == "DISABLED")) )
| map( select(.Tenants != []) )

当然,在管道中更早地执行选择会更有效率——无论如何,一定要这样做!


推荐阅读