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.
Raw Data
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' },
],
};
Desired data after filtering "home" and "work"
Array to use as filtering terms
const filterTags = ['home', 'work']
Data we are left with
{
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()
.
CodePudding user response:
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);
CodePudding user response:
Similar to SSM's answer, but if you do not wish to include days with no results
- Convert the object to an array using Object.entries.
- filter the content using includes on the filterTags
- only add the day with result of the filter returns 1 or more 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)