How to filter nested array? I have an array with users, I need to display the roles of the selected user in , but it turns out to be a huge nesting and a whole bunch of iterations, how to avoid this and get something like:
const options = [
{ value: 1, label: "admin" },
{ value: 0, label: "moderator" }
];
I do
const arr = [
{
users: [
{
id: 1,
login: "alex",
roles: [
{ id: 0, name: "admin" },
{ id: 1, name: "moderator" }
]
},
{
id: 2,
login: "bob",
roles: [{ id: 0, name: "viewer" }]
}
]
}
];
const rolesOptions = arr.filter(({ users }) =>
users
.filter(({ id }) => id === 1)
.map(({ roles }) =>
roles.map(({ id, name }) => ({ label: name, value: id }))
)
);
console.log(rolesOptions);
CodePudding user response:
You can use .flatMap()
to map your outer arr
of object. For each inner nested object, you can filter it to only keep objects matching the id
of 1
(as you've done). You can then use .flatMap()
on the filtered inner array to map each role to its re-keyed object with label
and name
. The .flatMap()
methods then merge the returned array results into one resulting array:
const arr = [ { users: [ { id: 1, login: "alex", roles: [ { id: 0, name: "admin" }, { id: 1, name: "moderator" } ] }, { id: 2, login: "bob", roles: [{ id: 0, name: "viewer" }] } ] } ];
const options = arr.flatMap(({users}) => users
.filter(({ id }) => id === 1)
.flatMap(({roles}) => roles.map(({ id, name }) => ({ label: name, value: id })))
);
console.log(options);
If you know for certain that there can only be one user object within each object's users
array with a given id
, then you can make your code more efficient by using .find()
so that it returns as soon as the object user with the id is found:
const arr = [{ users: [{ id: 1, login: "alex", roles: [{ id: 0, name: "admin" }, { id: 1, name: "moderator" }] }, { id: 2, login: "bob", roles: [{ id: 0, name: "viewer" }] }] }];
const options = arr.flatMap(({users}) => users
.find(({ id }) => id === 1)
?.roles.map(({ id, name }) => ({ label: name, value: id })) ?? []
);
console.log(options);
The above uses optional chaining (?.
) to check that an user with the id can be found, and the nullish coalescing operator (??
) to return an empty array if the id
coudln't be found.
CodePudding user response:
You needed to use map
instead of filter
on the outside array arr
flat
then flattens the remaining objects
const arr = [
{
users: [
{
id: 1,
login: "alex",
roles: [
{ id: 0, name: "admin" },
{ id: 1, name: "moderator" }
]
},
{
id: 2,
login: "bob",
roles: [{ id: 0, name: "viewer" }]
}
]
}
];
const rolesOptions = arr.map(({ users }) =>
users
.filter(({ id }) => id === 1)
.map(({ roles }) =>
roles.map(({ id, name }) => ({ label: name, value: id }))
)
).flat(2);
console.log(rolesOptions)
CodePudding user response:
This is what I came up with:
const arr = [
{
users: [
{
id: 1,
login: "alex",
roles: [
{ id: 0, name: "admin" },
{ id: 1, name: "moderator" }
]
},
{
id: 2,
login: "bob",
roles: [{ id: 0, name: "viewer" }]
}
]
}
];
const users = getUsers(arr)
const rolesOptions = getRolesOptions(users)
console.log(rolesOptions)
function getUsers(arr) {
let res = [] // The result array
arr
.filter(({ users }) => users) // Filters to find every instance that has a "users" JSON key
.map(({ users }) => users) // Maps out the users into multiple arrays
.forEach(users => { // Adds each array of users into one array
users.forEach(user => {
res.push(user)
})
})
return res
}
function getRolesOptions(users) {
let res = [] // The result array
users.forEach(user => {
user.roles.forEach(({ name, id }) => { // For every user it pushes the role in formate { name, id } to the result array
res.push({ label: name, value: id })
})
})
return res
}
There probably is a neater way. Sorry if it is not what you asked for