Reputation: 7
I'm making a note-taking app in React and I have some data that looks like this. I'm wanting to filter it so that only the objects which contain a tag in an array remain, and the rest are removed.
const obj = {
Mon: [
{ id: 1, content: 'Some text', tag: 'home' },
{ id: 2, content: 'Some text', tag: 'work' },
{ id: 3, content: 'Some text', tag: 'project' },
],
Tue: [
{ id: 4, content: 'Some text', tag: 'project' },
{ id: 5, content: 'Some text', tag: 'moving' },
],
Wed: [
{ id: 6, content: 'Some text', tag: 'home' },
{ id: 7, content: 'Some text', tag: 'home' },
{ id: 8, content: 'Some text', tag: 'work' },
],
};
const filterTags = ['home', 'work']
{
Mon: [
{ id: 1, content: 'Some text', tag: 'home' },
{ id: 2, content: 'Some text', tag: 'work' },
],
Wed: [
{ id: 6, content: 'Some text', tag: 'home' },
{ id: 7, content: 'Some text', tag: 'home' },
{ id: 8, content: 'Some text', tag: 'work' },
],
};
The reason for wanting to filter using an array is because I want a user to be able to click on the tags for the notes they want to see (these tags are currently stored in a useState()
).
With the remaining data after filtering, I plan to map through it and render the relevant elements like this:
<>
{Object.entries(sortedNotesData).map(
([noteDate, noteContent], i) => (
<div key={i}>
<NoteDate noteDate={noteDate} />
<div className="column">
{noteContent
.map((note) => (
<>
<NoteCard
key={note.id}
id={note.id}
content={note.content}
tag={note.tag}
/>
</>
))}
</div>
</div>
)
)}
</>
Any suggestions on a best practice way of filtering the raw data would be brilliant, including whether it would be best to handle the data filtering in a function outside of render()
, or whether it can be done inline just before the .map()
.
Upvotes: 0
Views: 657
Reputation: 8148
Convert the object to an array using Object.entries.
Map over the nested array and filter the values using the filterTags
array.
Remove days that have no matching items in them.
Finally convert the nested array back to an object using Object.fromEntries
const obj = {
Mon: [
{ id: 1, content: "Some text", tag: "home" },
{ id: 2, content: "Some text", tag: "work" },
{ id: 3, content: "Some text", tag: "project" },
],
Tue: [
{ id: 4, content: "Some text", tag: "project" },
{ id: 5, content: "Some text", tag: "moving" },
],
Wed: [
{ id: 6, content: "Some text", tag: "home" },
{ id: 7, content: "Some text", tag: "home" },
{ id: 8, content: "Some text", tag: "work" },
],
},
filterTags = ["home", "work"],
filteredObj = Object.fromEntries(
Object.entries(obj)
.map(([key, value]) => [
key,
value.filter(({ tag }) => filterTags.includes(tag)),
])
.filter(([, value]) => value.length)
);
console.log(filteredObj);
You can also keep the days that have no matching items by simply removing the last filter.
const obj = {
Mon: [
{ id: 1, content: "Some text", tag: "home" },
{ id: 2, content: "Some text", tag: "work" },
{ id: 3, content: "Some text", tag: "project" },
],
Tue: [
{ id: 4, content: "Some text", tag: "project" },
{ id: 5, content: "Some text", tag: "moving" },
],
Wed: [
{ id: 6, content: "Some text", tag: "home" },
{ id: 7, content: "Some text", tag: "home" },
{ id: 8, content: "Some text", tag: "work" },
],
},
filterTags = ["home", "work"],
filteredObj = Object.fromEntries(
Object.entries(obj).map(([key, value]) => [
key,
value.filter(({ tag }) => filterTags.includes(tag)),
])
);
console.log(filteredObj);
Upvotes: 0
Reputation: 1943
Similar to SSM's answer, but if you do not wish to include days with no results
.
const obj = {
Mon: [
{ id: 1, content: 'Some text', tag: 'home' },
{ id: 2, content: 'Some text', tag: 'work' },
{ id: 3, content: 'Some text', tag: 'project' },
],
Tue: [
{ id: 4, content: 'Some text', tag: 'project' },
{ id: 5, content: 'Some text', tag: 'moving' },
],
Wed: [
{ id: 6, content: 'Some text', tag: 'home' },
{ id: 7, content: 'Some text', tag: 'home' },
{ id: 8, content: 'Some text', tag: 'work' },
],
};
const filterTags = ['home', 'work']
//this will hold an object of results
let filteredResults = {};
Object.entries(obj).forEach(day => {
const name = day[0];
const filtered = day[1].filter(content => filterTags.includes(content.tag))
if (filtered.length > 0) {
filteredResults[name] = filtered
}
})
console.log(filteredResults)
Upvotes: 0