简体   繁体   中英

Steam API, different json format

Recently i integrated CSGO stats in my discord bot, but today i saw that for almost every player the API sends a different json data.

Here 2 examples:

https://jsonblob.com/58688d30-26d0-11e8-b426-7b3214778399 https://jsonblob.com/52ed0c3f-26d0-11e8-b426-43058df4a5a6

My question was how to request the data properly so a win is really a win and not a kill.

  .addField('**Wins:**', `${object.playerstats.stats[5].value}`, true) .addField('**Time played:**', `${object.playerstats.stats[2].value}` + ' minutes', true) .addField('**Kills:**', `${object.playerstats.stats[0].value}`, true) .addField('**Deaths:**', `${object.playerstats.stats[1].value}`, true) .addField('**Bombs planted:**',`${object.playerstats.stats[3].value}`, true) .addField('**Money earned:**',`${object.playerstats.stats[7].value}`, true) .addField('**Knife kills:**',`${object.playerstats.stats[9].value}`, true) .addField('**Headshot kills:**',`${object.playerstats.stats[24].value}`, true) .addField('**Dominations:**',`${object.playerstats.stats[39].value}`, true) .addField('**Rounds played:**',`${object.playerstats.stats[44].value}`, true) 

The name property of stats items appear to be unique enough to find. You can use array.find to look for the correct stat by name.

const stats = object.playerstats.stats
const totalKills = stats.find(s => s.name === 'total_kills').value
const totalDeaths = stats.find(s => s.name === 'total_deaths').value

Taking it further, you can use array.reduce to generate an object whose key is name and value is value for each item in the array. This way, you access it like an object.

const stats = object.playerstats.stats
const statsObj = stats.reduce((c, e) => (c[e.name] = e.value, c), {})

const totalKills = statsObj.total_kills
const totalDeaths = statsObj.total_deaths

Rather than trying to reference the array indexes, why not convert the API response into an easier-to-parse format?

// do this once...
let playerStats = {};
object.playerstats.stats.forEach(s => playerStats[s.name] = s.value);

// ...then you can use the playerStats variable however you need:
.addField('**Kills:**', `${playerStats.total_kills}`, true)
.addField('**Wins:**', `${playerStats.total_wins}`, true)

The stats array is just not sorted. you can use .find() to get the correct entry from the stats.

for example

const totalWins = object.playerstats.stats.find(stat => {
    return stat.name === 'total_wins';
});
.addField('**Wins:**', `${totalWins.value}`, true)

You are approching this problem the wrong way.

JSON is not a format that is ordered. What that means is that there is no guarantee that the JSON data will return in the same order everytime. It is not a default of the API.

There is one way you could still use your way: by sorting the 'stats' array by name. but it is a long operation and not a very good idea.

The way do to this is to do a lookup by name. For example, if you want to find the wins, you do this :

object.playerstats.stats.find(elem => elem.name === 'total_wins').value;

The find function does a lookup and returns the first element matching the predicate (elem.name === 'total_wins'). It returns null if not element matched the predicate (so be careful here).

You could do a function that returns a value for you :

findValue(statsArray, name) {
    const entry = statsArray.find(elem => elem.name === name);
    return entry ? entry.value : '?';
}

And then your code would look like this :

 ...
 .addField('**Wins:**', findValue(object.playerstats.stats, 'total_wins'), true)
 ...

The main thing here is : never assume fields in a JSON will return the same every time. Always use lookup, and not indexes (unless it is sorted).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM