0

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().

2 Answers 2

0
  • 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);

Sign up to request clarification or add additional context in comments.

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.