如何对比两个对象数组过滤非匹配项,保留数据库球员自定义Active状态
问题描述
我现在发起了两个GET 请求,一个请求本地数据库,另一个请求第三方API。
我手里有两个对象数组:数据库返回的数组存储球员数据,部分球员的Active状态被设置为true或false(我正在开发应用前端功能,支持用户控制球员是否启用);API返回的数组同样包含球员数据,但所有球员的Active状态默认均为true,该数据每24小时拉取一次,会通过PUT 请求发送到数据库并覆盖所有原有数据。
需求
如果数据库中某球员的Active状态为false,我需要在API返回的数组中忽略该对象,仅用'Active': true的球员数据更新数据库。
以下是数据库存储的数组示例:
[{ "PlayerID": 12345, "Team": "ABC", "FirstName": "Patrick", "LastName": "Star", "Position": "RB", "Active": false, "__v": 0 }, { "PlayerID": 67890, "Team": "DEF", "FirstName": "Spongebob", "LastName": "Squarepants", "Position": "WR", "Active": true, "__v": 0 }]
以下是API返回的数组示例,请注意Patrick Star的Active状态为true:
[{ "PlayerID": 12345, "Team": "ABC", "FirstName": "Patrick", "LastName": "Star", "Position": "RB", "Active": true, "__v": 0 }, { "PlayerID": 67890, "Team": "DEF", "FirstName": "Spongebob", "LastName": "Squarepants", "Position": "WR", "Active": true, "__v": 0 }]
我需要对比这两个数组,返回仅包含有效启用球员的新数组(上述示例中为Spongebob Squarepants),这样数据库中'Active': false的球员不会被更新覆盖。我打算用PlayerID作为参考字段区分球员并做过滤,但目前无法实现。
编辑:以下是我要实现该功能的现有代码:
function getPlayers() { const APIplayersURL = "someURL"; const DBoffensivePlayersURL = "http://localhost:4000/api/offensiveplayers"; axios.get(DBoffensivePlayersURL).then((res) => { const inactivePlayers = res.data; // Filter out all of the active players const dbArr = inactivePlayers.filter( players => players.Active === false ); axios.get(APIplayersURL).then((res) => { const players = res.data; // Filter out all players except for QB, RB and WR const offensivePlayers = players.filter( players => players.Position === "QB" || players.Position === "RB" || players.Position === "WR" ); // Give me all active QBs, RBs, and WRs const apiArr = offensivePlayers.filter( offensivePlayers => offensivePlayers.Status === "Active" ); const result = dbArr.filter( (obj) => obj.Active && apiArr.some((o) => o.PlayerID === obj.PlayerID) ); console.log(result); const config = { headers: { "Content-Type": "application/json", "Authorization": "x-auth-token", "Access-Control-Allow-Origin": "*" }, }; axios .put("http://localhost:4000/api/offensiveplayers", result, config) .then((res) => console.log(res)) .catch((err) => console.error(err)); console.log("Players updated successfully"); }); }); } // Runs the getPlayers every 24 hours setInterval(getPlayers, 86400000);
解决方案
你现有代码的核心问题是逻辑搞反了:你从数据库拉取数据后,dbArr只保留了Active: false的球员,后续过滤又判断obj.Active,最终得到的result必然是空数组。
正确逻辑应该是:先提取数据库里所有禁用球员的PlayerID存为集合,再把API返回的合格球员中,属于禁用集合的球员剔除,剩下的就是要更新到数据库的数据。用Set存储禁用ID的查询效率比数组更高,数据量大的时候优势更明显。
修正后的代码如下:
function getPlayers() { const APIplayersURL = "someURL"; const DBoffensivePlayersURL = "http://localhost:4000/api/offensiveplayers"; axios.get(DBoffensivePlayersURL).then((res) => { const allDbPlayers = res.data; // 提取所有被禁用的球员ID,存入Set提升查询效率 const inactivePlayerIds = new Set( allDbPlayers .filter(player => player.Active === false) .map(player => player.PlayerID) ); axios.get(APIplayersURL).then((res) => { const apiPlayers = res.data; // 过滤出位置符合要求的进攻组球员 const offensivePlayers = apiPlayers.filter( player => ["QB", "RB", "WR"].includes(player.Position) ); // 过滤出API返回的状态为启用的球员 const validApiPlayers = offensivePlayers.filter( player => player.Status === "Active" ); // 剔除数据库中被禁用的球员,得到最终更新列表 const result = validApiPlayers.filter( player => !inactivePlayerIds.has(player.PlayerID) ); console.log(result); const config = { headers: { "Content-Type": "application/json", "Authorization": "x-auth-token", "Access-Control-Allow-Origin": "*" }, }; axios .put("http://localhost:4000/api/offensiveplayers", result, config) .then((res) => console.log(res)) .catch((err) => console.error(err)); console.log("球员更新成功"); }); }); } // 每24小时执行一次getPlayers setInterval(getPlayers, 86400000);
内容的提问来源于stack exchange,提问作者KyleOli

