How to filter an array in array of objects in Javascript?
Categories:
Filtering Arrays within Objects in JavaScript

Learn various JavaScript techniques to efficiently filter arrays nested within objects, covering common use cases and best practices.
Working with complex data structures is a common task in JavaScript development. Often, you'll encounter an array of objects, where each object itself contains another array. Filtering these nested arrays based on specific criteria requires a good understanding of array methods and object manipulation. This article will guide you through several effective methods to achieve this, from simple filter
and map
combinations to more advanced techniques.
Understanding the Problem: Nested Data Structures
Before diving into solutions, let's visualize the type of data structure we're dealing with. Imagine a list of users
, where each user object has a name
and an array of roles
. Our goal might be to find users who have a specific role, or perhaps to return users with only certain roles filtered out from their roles
array.
graph TD A[Array of User Objects] A --> B{User Object 1} A --> C{User Object 2} B --> B1[name: "Alice"] B --> B2[roles: ["admin", "editor"]] C --> C1[name: "Bob"] C --> C2[roles: ["viewer"]] B2 --> B2a["admin"] B2 --> B2b["editor"] C2 --> C2a["viewer"] style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#bbf,stroke:#333,stroke-width:2px style C fill:#bbf,stroke:#333,stroke-width:2px
Representation of an array of objects with nested arrays.
Method 1: Filtering Parent Objects Based on Nested Array Content
A common requirement is to filter the top-level array of objects, keeping only those objects whose nested array contains at least one element matching a certain condition. This can be achieved using a combination of filter()
and some()
.
const users = [
{ id: 1, name: 'Alice', roles: ['admin', 'editor'] },
{ id: 2, name: 'Bob', roles: ['viewer'] },
{ id: 3, name: 'Charlie', roles: ['admin'] },
{ id: 4, name: 'David', roles: ['guest'] }
];
// Find users who have the 'admin' role
const admins = users.filter(user =>
user.roles.some(role => role === 'admin')
);
console.log(admins);
/*
[
{ id: 1, name: 'Alice', roles: ['admin', 'editor'] },
{ id: 3, name: 'Charlie', roles: ['admin'] }
]
*/
Filtering parent objects using filter()
and some()
.
some()
method is highly efficient for checking existence. It returns true
as soon as it finds a matching element and stops iterating, which can save performance on large arrays.Method 2: Filtering Nested Arrays and Returning Modified Objects
Sometimes, you don't want to filter the parent objects, but rather modify them by filtering their internal arrays. For instance, you might want to return all users, but for each user, only include specific roles in their roles
array. This involves using map()
to iterate over the parent array and filter()
for the nested array.
const users = [
{ id: 1, name: 'Alice', roles: ['admin', 'editor', 'developer'] },
{ id: 2, name: 'Bob', roles: ['viewer', 'editor'] },
{ id: 3, name: 'Charlie', roles: ['admin'] }
];
// Return all users, but only include 'admin' or 'editor' roles for each
const usersWithFilteredRoles = users.map(user => ({
...user, // Spread existing user properties
roles: user.roles.filter(role => role === 'admin' || role === 'editor')
}));
console.log(usersWithFilteredRoles);
/*
[
{ id: 1, name: 'Alice', roles: ['admin', 'editor'] },
{ id: 2, name: 'Bob', roles: ['editor'] },
{ id: 3, name: 'Charlie', roles: ['admin'] }
]
*/
Filtering nested arrays using map()
and filter()
.
...user
) is crucial here to create a shallow copy of the user object. This prevents direct mutation of the original users
array, adhering to good functional programming practices.Method 3: Combining Both: Filter Parent and Filter Nested Arrays
What if you need to do both? Filter the parent objects based on a condition in their nested array, AND then filter the nested array itself for the remaining objects. This requires a two-step process, often chaining filter()
and map()
.
const users = [
{ id: 1, name: 'Alice', roles: ['admin', 'editor', 'developer'] },
{ id: 2, name: 'Bob', roles: ['viewer', 'editor'] },
{ id: 3, name: 'Charlie', roles: ['admin'] },
{ id: 4, name: 'David', roles: ['guest'] }
];
// 1. Filter users who have 'admin' role
// 2. For those users, only keep 'admin' or 'editor' roles
const filteredAndModifiedUsers = users
.filter(user => user.roles.some(role => role === 'admin')) // Step 1: Filter parent
.map(user => ({
...user,
roles: user.roles.filter(role => role === 'admin' || role === 'editor') // Step 2: Filter nested
}));
console.log(filteredAndModifiedUsers);
/*
[
{ id: 1, name: 'Alice', roles: ['admin', 'editor'] },
{ id: 3, name: 'Charlie', roles: ['admin'] }
]
*/
Chaining filter()
and map()
for combined filtering.
filter()
) and then mapping to modify nested arrays (with map()
) is generally more efficient than the other way around, as it reduces the number of objects map()
needs to process.