I have an array which I'm trying to filter based on a certain nested value, without getting any other elements.
const arrayData = [
{
country: "Country X",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'John', status:'Active' },{ name: 'Rob', status:'Suspended' }]
},
{
gameTitle: 'Game2',
players: [{ name: 'Saly', status:'Blocked' }]
},
]
},
{
country: "Country Y",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'Sindy', status:'Pending' },{ name: 'someone', status:'Rejected' }]
},
{
gameTitle: 'Game2',
players: [{ name: 'Alex', status:'New' },{ name: 'Nic', status:'Old' }]
},
]
},
];
What I have tried:
let output = arrayData.filter(eachVal => {
let opt = eachVal.games.some((
{ players }) => players
.some(({ status}) => status === 'Active'));
return opt;
})
Expected result for finding all players with value status : 'Active':
{
country: "Country X",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'John', status:'Active' }]
}
]
}
But the result:
[{"country":"Country X","games":[{"gameTitle":"Game1","players":[{"name":"John","status":"Active"},{"name":"Rob","status":"Suspended"}]},{"gameTitle":"Game2","players":[{"name":"Saly","status":"Blocked"}]}]}]
-
um, if you want the players with active status, why do you want the country and the games array?The Bomb Squad– The Bomb Squad2021年01月09日 13:25:25 +00:00Commented Jan 9, 2021 at 13:25
-
@TheBombSquad Because I need to display their values as well!Sam– Sam2021年01月09日 13:28:16 +00:00Commented Jan 9, 2021 at 13:28
-
@Sam this question might help stackoverflow.com/questions/38375646/…Ozgur Sar– Ozgur Sar2021年01月09日 13:29:46 +00:00Commented Jan 9, 2021 at 13:29
-
I've seen it before, but the filter applied there for the first level only, and I couldn't do it inside the players list. @OzgurSarSam– Sam2021年01月09日 13:38:31 +00:00Commented Jan 9, 2021 at 13:38
-
just solved.. nested filter logic i usedThe Bomb Squad– The Bomb Squad2021年01月09日 14:19:47 +00:00Commented Jan 9, 2021 at 14:19
4 Answers 4
Try this:
arrayData.map(({country, games: g}) => {
const games = g.map((g) => {
const players = g.players.filter((p) => p.status === 'Active')
return {...g, players}
})
.filter(({players}) => players.length > 0)
return {country, games}
}).filter(({games}) => games.length>0)
Comments
The logic is nested filter through each level and assigning the finds back to their respective places and using forEach logic to see if an object has an "Active" value
const arrayData = [
{
country: "Country X",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'John', status:'Active' },{ name: 'Rob', status:'Suspended' }]
},
{
gameTitle: 'Game2',
players: [{ name: 'Saly', status:'Blocked' }]
},
]
},
{
country: "Country Y",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'Sindy', status:'Pending' },{ name: 'someone', status:'Rejected' }]
},
{
gameTitle: 'Game2',
players: [{ name: 'Alex', status:'New' },{ name: 'Nic', status:'Old' }]
},
]
},
];
//answer
let arr=JSON.parse(JSON.stringify(arrayData))
arr=arr.filter(a=>{
let f=a.games; let i=false
f=f.filter(b=>{
let x=b.players; let j=false
x=x.filter(c=>c.status=="Active")
x.forEach(c=>{if(c.status=="Active"){j=true}})
b.players=x; return j
})
f.forEach(b=>{
b.players.forEach(c=>{if(c.status=="Active"){i=true}})
})
a.games=f; return i
})
console.log(arr)
Comments
It's quite easy. You just need some map and filter:
const arrayData = [
{
country: "Country X",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'John', status:'Active' },{ name: 'Rob', status:'Suspended' }]
},
{
gameTitle: 'Game2',
players: [{ name: 'Saly', status:'Blocked' }]
},
]
},
{
country: "Country Y",
games: [
{
gameTitle: 'Game1',
players: [{ name: 'Sindy', status:'Pending' },{ name: 'someone', status:'Rejected' }]
},
{
gameTitle: 'Game2',
players: [{ name: 'Alex', status:'New' },{ name: 'Nic', status:'Old' }]
},
]
},
];
/*------------------------------- This is the answer -------------------------------*/
let result = arrayData.map(a => ({...a, games: a.games.map(g => ({...g, players: g.players.filter(p => p.status === 'Active')})).filter(g => g.players.length)})).filter(a => a.games.length)
/*----------------------------------------------------------------------------------*/
console.log(result)
Comments
I'd "recursively" select the valid elements at each level and map on each filtered array to build the correct output:
const selectActivePlayers = (players) => players.filter(player => player.status === "Active");
const selectValidGames = (games) => games.filter(game => selectActivePlayers(game.players).length > 0)
const selectValidCountries = (countries) => countries.filter(country => selectValidGames(country.games).length > 0);
const cleanCountries = selectValidCountries(arrayData).map(country => ({
...country,
games: selectValidGames(country.games).map(game => ({
...game,
players: selectActivePlayers(game.players)
}))
}))
Output:
[
{
"country": "Country X",
"games": [
{
"gameTitle": "Game1",
"players": [
{
"name": "John",
"status": "Active"
}
]
}
]
}
]