Как я могу сгладить этот поток объектов, не создавая повторяющихся объектов?

Я хочу использовать реляционную базу данных для анализа информации из JSON API от Songkick для локальных событий.

Объекты событий сложны и глубоко вложены, поэтому я хочу отфильтровать и сгладить объекты событий и преобразовать их в 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"
}

Каждый объект выглядит правильно, но их слишком много! Дублируются объекты «Кэти Би» и «Бекки Хилл».

Как правильно сделать это в jq?


person Iain Samuel McLean Elder    schedule 31.10.2014    source источник


Ответы (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, поэтому вам придется немного его сгладить, прежде чем вы начнете собирать результаты.

person Jeff Mercado    schedule 31.10.2014
comment
На что следует обратить внимание при использовании нескольких .[] фильтров. Если для каждого массива существует более одного значения, он будет создавать результат для каждой комбинации значений в массивах, что, вероятно, не то, что вы хотите. - person Jeff Mercado; 31.10.2014
comment
Спасибо! На самом деле я не заметил, что объекты были перестановками, а не дубликатами. Другой важный момент для обучения - использование map для итеративного применения фильтра с сохранением списка. - person Iain Samuel McLean Elder; 02.11.2014