【问题标题】:Javascript : Filter a JSON object from API call to only get the infos I needJavascript:从 API 调用中过滤 JSON 对象以仅获取我需要的信息
【发布时间】:2021-08-24 12:59:31
【问题描述】:

我正在尝试创建一个小项目来处理 API 调用。我创建了一个异步,它使用 MusicBrainz API 恢复有关曲目的信息。你可以点击那里查看请求的结果:https://musicbrainz.org/ws/2/recording/5935ec91-8124-42ff-937f-f31a20ffe58f?inc=genres+ratings+releases+artists&fmt=json(我选择了从 AC/DC 到地狱的高速公路)。

这是我在重新处理我的请求的 JSON 响应时得到的结果:

export const GET_JSON = async function (url) {
  try {
    const res = await Promise.race([
      fetch(url),
      timeout(CONSTANTS.TIMEOUT_SEC),
    ]);
    const data = await res.json();

    if (!res.ok) throw new Error(`${data.message} (${res.status})`);
    return data;
  } catch (err) {
    throw err;
  }
};
export const loadTrackDetail = async function (id) {
  try {
    const trackData = await GET_JSON(
      encodeURI(
        `${CONSTANTS.API_URL}${id}?inc=genres+artists+ratings+releases&fmt=json`
      )
    );
    details.trackDetails = {
      trackTitle: trackData.title,
      trackID: trackData.id,
      trackLength: trackData.length ?? "No duration provided",
      trackArtists: trackData["artist-credit"].length
        ? trackData["artist-credit"]
        : "No information on artists",

      trackReleases: trackData["releases"].length
        ? trackData["releases"]
        : "No information on releases",

      trackGenres: trackData["genres"].length
        ? trackData["genres"]
        : "No information on genres",
      trackRating: trackData.rating.value ?? "No rating yet",
    };

    console.log(details.trackDetails);
  } catch (err) {
    throw err;
  }

现在这还不错,但是 release 属性例如是一个对象数组(每个对象都是存在轨道的特定版本)但是对于每个版本,我想“减少”仅反对其 id 和 title。其余的我不感兴趣。此外,我想说的是,例如,如果发布的标题与之前已经存在的标题相似,则不会将整个对象添加到新数组中。 我曾考虑过做一个 foreach 函数,但我只是不知道如何正确编写它,如果它实际上可能的话,如果我应该使用 array.map 例如,或其他迭代方法。 如果有人有一些在纯 JS(不是 Jquery !)中执行此操作的好方法,高效且干净,将不胜感激!

干杯

【问题讨论】:

  • 你的 API 结果不是一个数组而是一个对象。您实际上想要获得哪个idname
  • 是的,抱歉,我的意思是响应的“releases”属性返回一个数组。我编辑了问题!
  • 我没有看到name,但id 仅在第一级的每个数组中。
  • 该死,我明白你的意思,这也是@peinearydeveloment 在下面所说的。我编辑了我的问题:我的意思是每个版本的 title,而不是它的名称......抱歉造成混淆。

标签: javascript json api object


【解决方案1】:

有几件事让这个问题有点难以回答,但我相信下面的内容会让你找到正确的方向。

  1. 您没有包含 GET_JSON 方法,因此您的示例不完整,不能立即用于迭代。
  2. 在您带来的示例中,releases 数组中包含的对象没有 name 属性。我用下面的标题替换了名称来演示该方法。
  3. 你说

此外,我想说的是,例如,如果发布的名称 与之前已经存在的类似,整个 对象未添加到新数组中。

但你没有定义你认为会使发布相似的东西。

鉴于上述情况,如上所述,我假设您在说名称时指的是标题,并且我还假设构成类似版本的版本将是具有相同名称/标题的版本。

假设这些假设是正确的,我只需fetch 即可检索结果。响应上有一个 json 方法,该方法会将响应转换为 JSON 对象。 I map 每次发布到您感兴趣的较小数据集(id,title),然后 reduce 该数组以删除“重复”版本。

fetch('https://musicbrainz.org/ws/2/recording/5935ec91-8124-42ff-937f-f31a20ffe58f?inc=genres+ratings+releases+artists&fmt=json')
.then(m => m.json())
.then(j => {
  const reducedReleases = j.releases
                           .map(release => ({ id: release.id, name: release.title }))
                           .reduce(
                            (accumulator, currentValue, currentIndex, sourceArray) => {
                              if (!accumulator.find(a => a.name === currentValue.name)) {
                                accumulator.push(currentValue);
                              }
                              
                              return accumulator;
                            },
                            []);
  console.log(reducedReleases);
 });

【讨论】:

  • 太完美了!到目前为止,我还没有使用过多的 reduce,所以我必须努力理解这部分。是的,你是对的,我把房产名称弄错了,并在我原来的帖子中写了名字。我编辑了它,还添加了 GET_JSON 函数
【解决方案2】:
const releasesReduced = []
const titleNotExist = (title) => {
    return releasesReduced.every(release => {
        if(release.title === title) return false;
        return true
    })
}
trackData["releases"].forEach(release => {
    if (titleNotExist(release.title))
        releasesReduced.push({id: release.id, title: release.title})
})
console.log(releasesReduced)

【讨论】:

  • 这也很好用!第一个答案允许我直接在对象中完成所有操作,而无需在对象之外创建 const 和/或函数。不过,对于像我这样的初学者来说,你的更容易理解,所以谢谢你!
【解决方案3】:

数组details.trackDetails.trackReleases 具有从不同对象到idname 的路径。如果您的意思是:["release-events"]=>["area"]["id"]and["area"]["name"]` 那么请看下面的演示。

Demo 在每一层路径上使用flatMap() 来提取“release-events”,然后是“area”以返回一个对象数组

[{name: area.name, id: area.id}, {name: area.name, id: area.id},...]

然后将对数组运行到 for...of 循环中,并将每个唯一的 nameid 设置为 ES6 映射。然后它将 Map 作为对象返回。

{name: id, name: id, ...}

要查看此功能,请访问Plunker

const releaseEvents = (details.trackDetails.trackReleases) => {
  let trackClone = JSON.parse(JSON.stringify(objArr));
  let areas = trackClone.flatMap(obj => {
    if (obj["release-events"]) {
      let countries = obj["release-events"].flatMap(o => {
        if (o["area"]) {
          let area = {};
          area.name = o["area"]["name"];
          area.id = o["area"]["id"];
          return [area];
        } else {
          return [];
        }
      });
      return countries;
    } else {
      return [];
    }
  });
  let eventAreas = new Map();
  for (let area of areas) {
    if (!eventAreas.has(area.name)) {
      eventAreas.set(area.name, area.id);
    }
  }
  return Object.fromEntries([...eventAreas]);
};

console.log(releaseEvents(releases));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    相关资源
    最近更新 更多