0

I have below object.

const data = [
  {
    status: 1,
    date: '2020-12-01',
  },
  {
    status: 1,
    date: '2020-11-01',
  },
  {
    status: 2,
    date: '2020-12-01',
  },
  {
    status: 4,
    date: '2020-12-01',
  },
  {
    status: 5,
    date: '2020-12-01',
  }
]

I need to filter out records with status 4 and 5.

Also, need to have only latest record for status 1.

So the result would be like below.

 const data = [
      {
        status: 1,
        date: '2020-12-01',
      },
      {
        status: 2,
        date: '2020-12-01',
      },
]

This is what I have tried.

data.filter(obj => [1, 2, 3].includes(obj.status))
    .filter(obj => obj.status === 1)
    .sort((a, b) => new Date(b.date) - new Date(a.date))

But here I am losing object with other status.

I could do by storing filtered result first and then sorting and picking up the latest record, and use something like below

const result = filteredResult.push(latestRecordWithStatusOne)

But, is it possible to achieve this using the same chaining?

Magnetaar
  • 51
  • 6

3 Answers3

1

After filtering for status being 1,2 or 3, you can then use Array.reduce to create an object with the latest date for each status value. Since the other status values don't have multiple entries, it's safe to use this code for all of them. You can then use Object.values to create your desired output array:

const data = [{
    status: 1,
    date: '2020-12-01',
  },
  {
    status: 1,
    date: '2020-11-01',
  },
  {
    status: 2,
    date: '2020-12-01',
  },
  {
    status: 4,
    date: '2020-12-01',
  },
  {
    status: 5,
    date: '2020-12-01',
  }
]

const out = Object.values(data
  .filter(obj => [1, 2, 3].includes(obj.status))
  .reduce((c, obj) => {
    c[obj.status] = c[obj.status] || obj;
    if (obj.date > c[obj.status].date)
      c[obj.status].date = obj.date
    return c;
  }, {})
);
console.log(out);
Nick
  • 138,499
  • 22
  • 57
  • 95
  • @Nick Will comparing them without formatting as `Date` will work fine? I mean, here you are comparing just string, and still it's working fine. How? – Magnetaar Dec 07 '20 at 04:16
  • 1
    @Magnetaar it works because the dates are in ISO format `YYYY-MM-DD` and so they can be compared directly as strings – Nick Dec 07 '20 at 04:17
  • @Magnetaar see for example https://stackoverflow.com/questions/13715561/compare-iso-8601-date-strings-in-javascript – Nick Dec 07 '20 at 04:19
0

you can try:

const data = [{    status: 1,    date: '2020-12-01',  },
  {    status: 1,    date: '2020-11-01',  },
  {    status: 2,    date: '2020-12-01',  },
  {    status: 4,    date: '2020-12-01',  },
  {    status: 5,    date: '2020-12-01',  }
]
console.log([...new Set(Object.values(data
  .filter(obj => [1, 2, 3].includes(obj.status))).map(item => item.status))])
Tí Sún
  • 11
  • 1
-1

You can do this in one go with a reduce function. Ignore the 4/5 status and check for newest status 1 and replace if needed. Otherwise, add the value.

const data = [{
        status: 1,
        date: '2020-12-01',
    },
    {
        status: 1,
        date: '2020-11-01',
    },
    {
        status: 2,
        date: '2020-12-01',
    },
    {
        status: 4,
        date: '2020-12-01',
    },
    {
        status: 5,
        date: '2020-12-01',
    }
]

const filtered = data.reduce((accumulator, currentValue, index, array) => {
    if ([4, 5].includes(currentValue.status)) {
            // don't add value since it's a status 4/5
        return accumulator;
    } else if (currentValue.status === 1) {
        // currentValue status is 1 so check if there is already one in the result
        const index = accumulator.findIndex(obj => obj.status === 1)
        if (index === -1) { 
                // no other status 1 so add it
            return [...accumulator, currentValue]
        } else if (accumulator[index].date < currentValue.date) {
                // newer status 1 so replace it
            return [...accumulator.slice(0, index), currentValue, ...accumulator.slice(index + 1)]
        } else {
                // already the newest so just return the current accumulator
            return accumulator;
        }
    } else {
            // any other status can just be added
        return [...accumulator, currentValue];
    }
}, []);

console.log(filtered)
Todd Skelton
  • 6,839
  • 3
  • 36
  • 48