raf
raf

Reputation: 195

Filter array of objects inside objects in typescript

I am trying to filter my object with an array of objects inside. Currently, I have this data.

 {
  tile: "test title",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-12345",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-10,-03",
      taskStatus: "On track"
    },
    {
      id: 102,
      dateAssigned: "2019-10,-03",
      taskStatus: "On track"
    }
  ]
},
{
  tile: "test title no. 2",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-54321",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-09,-03",
      taskStatus: "Overdue"
    }
  ]
},
{
  tile: "test title no. 3",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-99999",
  schedules: [
    {
      id: 103,
      dateAssigned: "2019-09,-03",
      taskStatus: "Open"
    }
  ]
}

I want to filter only "Open" and "Overdue" items.

this.urgentRequests = this.urgentRequests.filter(a => {
   return a.schedules.find(s => s.taskStatus !== 'On track');
});

Currently, it is not working. It is possible to filter and find at the same time?

I am still getting 'On track' items enter image description here

The expected output gets only data with overdue and open items. But right now its is returning all items including "On track"

{
  tile: "test title no. 2",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-54321",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-09,-03",
      status: "Overdue"
    }
  ]
},
{
  tile: "test title no. 3",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-99999",
  schedules: [
    {
      id: 103,
      dateAssigned: "2019-09,-03",
      status: "Open"
    }
  ]
}

Upvotes: 0

Views: 433

Answers (3)

Asad S
Asad S

Reputation: 2116

I think your code is almost correct,

// Your code
this.urgentRequests = this.urgentRequests.filter(a => {
  a.schedules.find(s => s.taskStatus !== 'On track');
});
  1. Change the s.taskStatus into s.status instead. If you look closely, the key name is status.
  2. Use a return statement. filter expects a function that return boolean as the input. In your case, your function not returning anything, thus returning undefined (computed to false).

So, the code should looks like this:

this.urgentRequests = this.urgentRequests.filter(a => {
  return a.schedules.find(s => s.status !== 'On track');
});

Edit: I added code snippet to make sure everything is working. And it does. You can check it below.

const items = [{
  tile: "test title",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-12345",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-10,-03",
      status: "On track"
    },
    {
      id: 102,
      dateAssigned: "2019-10,-03",
      status: "On track"
    }
  ]
},
{
  tile: "test title no. 2",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-54321",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-09,-03",
      status: "Overdue"
    }
  ]
},
{
  tile: "test title no. 3",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-99999",
  schedules: [
    {
      id: 103,
      dateAssigned: "2019-09,-03",
      status: "Open"
    }
  ]
}]

const targets = ["open", "overdue"];

const filterResult = items.filter(item => {
    return item.schedules.find(s => targets.includes(s.status.toLowerCase()))
})

console.log("I named the original array into 'items'.");
console.log("I add toLowerCase to make sure it wasn't typing issue.");
console.log("The results are: ", filterResult);
console.log("The result's schedules are: ", filterResult.map(a => a.schedules));
console.log(" No more 'On Track' right :) ");

NB: I'm using several new techniques but the idea is still the same.

Upvotes: 1

Brian McCutchon
Brian McCutchon

Reputation: 8584

You were on the right track, but your outer arrow function was missing a return and you should use some instead of find. You need to use return if your arrow function has braces around the body; I fixed this by dropping the braces. Also, you wrote taskStatus instead of status.

this.urgentRequests.filter(a =>
    a.schedules.some(s => s.status !== 'On track'))

Upvotes: 1

Derek Wang
Derek Wang

Reputation: 10193

Using Array.prototype.reduce, you can extract filtered items only.

const input = [{
  tile: "test title",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-12345",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-10,-03",
      status: "On track"
    },
    {
      id: 102,
      dateAssigned: "2019-10,-03",
      status: "On track"
    }
  ]
},
{
  tile: "test title no. 2",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-54321",
  schedules: [
    {
      id: 101,
      dateAssigned: "2019-09,-03",
      status: "Overdue"
    }
  ]
},
{
  tile: "test title no. 3",
  id: 1,
  createdBy: "[email protected]",
  comments: "",
  taskId: "TK-99999",
  schedules: [
    {
      id: 103,
      dateAssigned: "2019-09,-03",
      status: "Open"
    }
  ]
}];

const output = input.reduce((acc, cur) => {
  const schedules = cur.schedules.filter(({status}) => status === 'Open' || status === 'Overdue');
  if (schedules.length > 0) {
    acc.push({
      ...cur,
      schedules
    });
  }
  return acc;
}, []);
console.log(output);

Upvotes: 2

Related Questions