【问题标题】:How can I flatten this object stream without creating duplicate objects?如何在不创建重复对象的情况下展平此对象流?
【发布时间】:2014-10-31 01:19:39
【问题描述】:

我想使用关系数据库来分析来自 Songkick 的JSON API for local events 的信息。

其中的事件对象复杂且嵌套很深,因此我想过滤和展平事件对象并将它们转换为 CSV,以便我可以使用标准工具加载它们。

我可以使用 jq 过滤和展平事件吗?

来自 API 的典型响应太大,无法在此处显示。我将展示一个具有相同相对结构的简化版本。

将过滤器.resultsPage.results.event[] 应用于响应会产生这样的事件对象流。

{
  "start": {
    "date": "2014-10-28"
  },
  "performance": [
    {
      "artist": {
        "displayName": "James Keelaghan",
        "identifier": [
          {
            "mbid": "08e5954e-efc0-4a95-95ac-d74cca5b79ff"
          }
        ]
      }
    }
  ],
  "venue": {
    "displayName": "Live At The Star"
  }
}
{
  "start": {
    "date": "2014-10-28"
  },
  "performance": [
    {
      "artist": {
        "displayName": "Katy B",
        "identifier": [
          {
            "mbid": "2df30b6c-997d-4c3f-abb5-5e0d6317ea57"
          }
        ]
      }
    },
    {
      "artist": {
        "displayName": "Becky Hill",
        "identifier": [
          {
            "mbid": "27bc6f5b-4585-49ab-8d7d-c62b59f5f010"
          }
        ]
      }
    }
  ],
  "venue": {
    "displayName": "O2 ABC"
    }
}

接下来我想为性能列表中的每个对象生成一个输出对象。这些新对象应具有包含事件对象的属性,例如日期和地点。

示例的正确输出如下所示。

{
  "venue_name": "Live At The Star",
  "artist_mbid": "08e5954e-efc0-4a95-95ac-d74cca5b79ff",
  "artist_name": "James Keelaghan",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_mbid": "2df30b6c-997d-4c3f-abb5-5e0d6317ea57",
  "artist_name": "Katy B",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_mbid": "2df30b6c-997d-4c3f-abb5-5e0d6317ea57",
  "artist_name": "Becky Hill",
  "start_date": "2014-10-28"
}

如果我忽略 mbid,这个 jq 过滤器会给我我想要的。

{
  start_date: .start.date,
  artist_name: .performance[].artist.displayName,
  venue_name: .venue.displayName
}

结果如下所示。

{
  "venue_name": "Live At The Star",
  "artist_name": "James Keelaghan",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_name": "Katy B",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_name": "Becky Hill",
  "start_date": "2014-10-28"
}

我也尝试了这个过滤器来获得 mbid。

{
  start_date: .start.date,
  artist_name: .performance[].artist.displayName,
  artist_mbid: .performance[].artist.identifier[].mbid,
  venue_name: .venue.displayName
}

结果如下所示。

{
  "venue_name": "Live At The Star",
  "artist_mbid": "08e5954e-efc0-4a95-95ac-d74cca5b79ff",
  "artist_name": "James Keelaghan",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_mbid": "2df30b6c-997d-4c3f-abb5-5e0d6317ea57",
  "artist_name": "Katy B",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_mbid": "27bc6f5b-4585-49ab-8d7d-c62b59f5f010",
  "artist_name": "Katy B",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_mbid": "2df30b6c-997d-4c3f-abb5-5e0d6317ea57",
  "artist_name": "Becky Hill",
  "start_date": "2014-10-28"
}
{
  "venue_name": "O2 ABC",
  "artist_mbid": "27bc6f5b-4585-49ab-8d7d-c62b59f5f010",
  "artist_name": "Becky Hill",
  "start_date": "2014-10-28"
}

每个对象看起来都不错,但是它们太多了! “凯蒂 B” 和“Becky Hill”对象是重复的。

在 jq 中执行此操作的正确方法是什么?

【问题讨论】:

    标签: jq songkick


    【解决方案1】:

    这个过滤器应该可以工作:

    .resultsPage.results.event | map(
        {
            venue_name: .venue.displayName,
            start_date: .start.date
        }
        +
        (.performance[].artist | {
            artist_mbid: .identifier[].mbid,
            artist_name: .displayName
        })
    )
    

    虽然字段的顺序不同,但如果需要,您可以随时重新排序:

    [
      {
        "venue_name": "Live At The Star",
        "start_date": "2014-10-28",
        "artist_mbid": "08e5954e-efc0-4a95-95ac-d74cca5b79ff",
        "artist_name": "James Keelaghan"
      },
      {
        "venue_name": "O2 ABC",
        "start_date": "2014-10-28",
        "artist_mbid": "2df30b6c-997d-4c3f-abb5-5e0d6317ea57",
        "artist_name": "Katy B"
      },
      {
        "venue_name": "O2 ABC",
        "start_date": "2014-10-28",
        "artist_mbid": "27bc6f5b-4585-49ab-8d7d-c62b59f5f010",
        "artist_name": "Becky Hill"
      }
    ]
    

    您正在尝试为每个对应的 performance 创建一个对象,因此在开始收集结果之前您必须将其压平一点。

    【讨论】:

    • 使用多个.[] 过滤器时必须注意的事项。如果每个数组有多个值,它将为数组中的每个值组合创建一个结果,这可能不是您想要的。
    • 谢谢!我实际上并没有注意到这些对象是排列而不是重复。这里另一个重要的学习点是使用map 在保留列表的同时迭代地应用过滤器。
    猜你喜欢
    • 2014-06-09
    • 2019-11-13
    • 2012-04-14
    • 1970-01-01
    • 2021-12-20
    • 2021-09-16
    • 2017-02-26
    • 1970-01-01
    • 2018-08-22
    相关资源
    最近更新 更多