You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS循环合并API数据时对象属性被覆盖致赔率缺失问题排查

问题描述

我编写了一段代码用于合并两个API的返回结果,仅保留业务所需的字段数据。我清楚当前实现方式并非最优,大家可能会疑惑为何我不直接使用赔率API,原因是赛事API包含历史数据,而赔率API不提供历史赛事的赔率数据。
目前遇到的异常现象:所有控制台输出日志都能正常打印主、客队的赔率赋值过程,但最终matchesAndOdds对象中仅保留了客队赔率,缺失主队赔率数据。
我猜测是不是odds对象的属性在循环执行过程中被意外覆盖了?

注:实际业务场景中matches和odds数组包含更多对象元素,此处为避免代码片段过长做了裁剪。

原实现代码:

const odds =
  [
    {
      "id": "dd7aff0584aee475b4d67ab83655f379",
      "sport_key": "aussierules_afl",
      "sport_title": "AFL",
      "commence_time": "2022-06-30T09:20:00Z",
      "home_team": "Brisbane Lions",
      "away_team": "Western Bulldogs",
      "bookmakers": [
        {
          "key": "unibet",
          "title": "Unibet",
          "last_update": "2022-06-29T12:14:33Z",
          "markets": [
            {
              "key": "h2h",
              "outcomes": [
                {
                  "name": "Brisbane Lions",
                  "price": 1.36
                },
                {
                  "name": "Western Bulldogs",
                  "price": 3.15
                }
              ]
            }
          ]
        }
      ]
    }
  ]

const matches =
  [
    {
      gametime: "2022-06-30T09:20:00.000Z",
      home_team: 'Brisbane Lions',
      away_team: 'Western Bulldogs',
      ground: 'Gabba',
      home_points: 108,
      away_points: 67,
      selected: null
    }
  ]

// 两个API的队伍名称映射字典
// ff = 赛事API  oa = 赔率API
  const ffToOa = { 
    "Western Bulldogs": "Western Bulldogs",
    "Brisbane Lions": "Brisbane Lions",
    "St Kilda": "St Kilda Saints",
    "Carlton": "Carlton Blues",
    "Sydney": "Sydney Swans",
    "Essendon": "Essendon Bombers",
    // 兼容墨尔本队更名Naarm的情况
    "Melbourne": "Melbourne Demons",
    "Naarm": "Melbourne Demons",
    "Adelaide": "Adelaide Crows",
    "North Melbourne": "North Melbourne Kangaroos",
    "Geelong": "Geelong Cats",
    "Collingwood": "Collingwood Magpies",
    "Gold Coast": "Gold Coast Suns",
    "West Coast": "West Coast Eagles",
    "Richmond": "Richmond Tigers",
    "Hawthorn": "Hawthorn Hawks",
    "GWS": "Greater Western Sydney Giants",
    "Port Adelaide": "Port Adelaide Power",
    "Fremantle": "Fremantle Dockers"
  }

let matchesAndOdds = [...matches];
matches.forEach((match, i) => {
  matchesAndOdds[i].odds = {};
  odds.forEach(odd => {
    if (odd.home_team === ffToOa[match.home_team] &&
      odd.away_team === ffToOa[match.away_team]) {
      odd.bookmakers.forEach(bookmaker => {
        bookmaker.markets[0].outcomes.forEach(outcome => {
          matchesAndOdds[i].odds[bookmaker.title] = {};
          console.log(`${i}. if (${outcome.name} === ${odd.home_team})`);
          console.log(`${i}. if (${outcome.name} === ${odd.away_team})`);
          console.log("-----------------------------------------");
          if (outcome.name === odd.home_team) {
            console.log(`${i}. home ${bookmaker.title} ${outcome.price}`);
            matchesAndOdds[i].odds[bookmaker.title].home = outcome.price;
            console.log(matchesAndOdds[i].odds[bookmaker.title].home);
          } else if (outcome.name === odd.away_team) {
            console.log(`${i}. away ${bookmaker.title} ${outcome.price}`);
            matchesAndOdds[i].odds[bookmaker.title].away = outcome.price;
            console.log(matchesAndOdds[i].odds[bookmaker.title].away);
          }
        })
      })
    }
  })
})

console.log(matchesAndOdds)
问题根因

你的猜测完全正确,odds属性确实在循环中被意外覆盖了。
问题出在遍历outcomes的循环内部:每次处理一个胜负结果时,都会执行matchesAndOdds[i].odds[bookmaker.title] = {},将当前博彩公司对应的赔率对象重置为全新空对象。
实际执行流程:

  • 处理第一个outcome(主队Brisbane Lions):先将Unibet对应的赔率对象置空,再写入home属性值1.36,此时控制台打印正常,主队赔率确实存在
  • 处理第二个outcome(客队Western Bulldogs):再次执行置空操作,直接把刚才存储了主队赔率的对象替换为空对象,再写入away属性值3.15
    循环结束后,对象中自然仅保留最后一次写入的客队赔率,之前赋值的主队数据在第二次置空时已经被删除。控制台能打印到主队赔率,是因为赋值操作完成后立刻打印,此时还未执行下一轮循环的覆盖逻辑。
修复方案

将博彩公司赔率对象的初始化逻辑,从outcomes循环内部移动到外层bookmaker循环中,每个博彩公司仅初始化一次赔率对象即可,无需在遍历每个胜负结果时重复重置。
修复后的核心循环代码:

matches.forEach((match, i) => {
  matchesAndOdds[i].odds = {};
  odds.forEach(odd => {
    if (odd.home_team === ffToOa[match.home_team] &&
      odd.away_team === ffToOa[match.away_team]) {
      odd.bookmakers.forEach(bookmaker => {
        // 初始化逻辑移到这里,每个bookmaker仅执行一次
        matchesAndOdds[i].odds[bookmaker.title] = {};
        bookmaker.markets[0].outcomes.forEach(outcome => {
          console.log(`${i}. if (${outcome.name} === ${odd.home_team})`);
          console.log(`${i}. if (${outcome.name} === ${odd.away_team})`);
          console.log("-----------------------------------------");
          if (outcome.name === odd.home_team) {
            console.log(`${i}. home ${bookmaker.title} ${outcome.price}`);
            matchesAndOdds[i].odds[bookmaker.title].home = outcome.price;
            console.log(matchesAndOdds[i].odds[bookmaker.title].home);
          } else if (outcome.name === odd.away_team) {
            console.log(`${i}. away ${bookmaker.title} ${outcome.price}`);
            matchesAndOdds[i].odds[bookmaker.title].away = outcome.price;
            console.log(matchesAndOdds[i].odds[bookmaker.title].away);
          }
        })
      })
    }
  })
})

修改后运行,最终输出的matchesAndOdds对象会同时保留主、客队的完整赔率数据。

内容的提问来源于stack exchange,提问作者dhenry437

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:27:22