Maniraj Murugan
Maniraj Murugan

Reputation: 9084

How to filter data based on date?

I am having an array ,

var data = [
    { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
    { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
    { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
    { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
    { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
    { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
    { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
    { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
    { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" }
    ];
    
    
data.forEach(function(result) {
   console.log(result.jobCategoryWithFromDate);
});

which gives the above result in console..

Here inside the foreach, i need to return the jobCategoryWithFromDate that has the latest date.

So expected result is, (same like below)..

ASSIST.. / Assistance [valid from 2019-01-01]
PROF.. / Professional [valid from 2019-01-01]
SEN.. / Senior [valid from 2019-01-01]

The above is the expected result and no change in it, just need to filter the result and return jobCategoryWithFromDate returns unique value with latest date..

Despite of the duplicate names, the filter needs to be handled based on the date (latest)..

Edit:

I have already accepted answer but later only i came to know that it is not working in all scenario, I am sorry for not testing it completely..

Don't know whether my explanation gone wrong, but thing is if the user name is same then filter needs to be done based on date or otherwise unique user with any date needs to be displayed.

Eg:

    var data = [
        { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
        { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
        { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
        { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
        { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
        { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
        { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
        { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
        { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" },
        { id: 10, jobCategoryWithFromDate: "Jun.. / Junior  [valid from 2018-01-01]" },
        { id: 11, jobCategoryWithFromDate: "Usr.. / User [valid from 2019-01-01]" },
        { id: 12, jobCategoryWithFromDate: "Man.. / Manager [valid from 2017-05-01]" }
    ];

function extractDate(string){
  return string.match(/[0-9]+-[0-9]+-[0-9]+/g);
}

var result = data.reduce((newestDates, currentItem)=>{
  if (newestDates.length===0) newestDates.push(currentItem);
  else {
    const dateDifference = new Date(extractDate(newestDates[0].jobCategoryWithFromDate)) - new Date(extractDate(currentItem.jobCategoryWithFromDate));
    
    if (dateDifference===0) newestDates.push(currentItem); // push items with the same date as newest found
    else if (dateDifference <= 0) newestDates = [currentItem]; // if item has newer date the original array gets replaced with one containing just this item
    // ignore case dateDifference >= 0 because we do not need to do anything with dates older than the newest found
  }
  return newestDates;
},[]);

console.log(result);

Here in this snippet look at the last three values, which have different username but same date with previous records..

Here expected result is i need to get all the last three records along with above three, because they are different user, like

ASSIST.. / Assistance [valid from 2019-01-01]
PROF.. / Professional [valid from 2019-01-01]
SEN.. / Senior [valid from 2019-01-01]
Jun.. / Junior  [valid from 2018-01-01]
Usr.. / User [valid from 2019-01-01]
Man.. / Manager [valid from 2017-05-01]

Upvotes: 1

Views: 346

Answers (5)

Krzysztof Krzeszewski
Krzysztof Krzeszewski

Reputation: 6714

Assuming that the date is in format YYYY-MM-DD you can just extract part of the string containing date from each element and create date object from it

EDIT: it seems that what you wanted was to get the last date for every user instead of just getting an array of entries with the latest dates, edited snippet to match it (you can edit part of regex extracting the name if you want a different comparison distinguishing between users)

var data = [
    { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
    { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
    { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
    { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
    { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
    { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
    { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
    { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
    { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" },
    { id: 10, jobCategoryWithFromDate: "Jun.. / Junior  [valid from 2018-01-01]" },
    { id: 11, jobCategoryWithFromDate: "Usr.. / User [valid from 2019-01-01]" },
    { id: 12, jobCategoryWithFromDate: "Man.. / Manager [valid from 2017-05-01]" }
];
    
function extractNameNDate(string){
  return [string.match(/^\w+/), string.match(/[0-9]+-[0-9]+-[0-9]+/g)];
}

var result = data.reduce((newestDates, currentItem)=>{
  const [user, date] = extractNameNDate(currentItem.jobCategoryWithFromDate);
  if (newestDates[user]) {
    // compare dates for given user
    const [storedUser, storedDate] = extractNameNDate(newestDates[user].jobCategoryWithFromDate);
    const dateDifference = new Date(storedDate) - new Date(date);
    
    if (dateDifference <= 0) newestDates[user] = currentItem;
    
  } else {
    newestDates[user]=currentItem;
  }
  return newestDates;
},{});

result = Object.values(result);

console.log(result);

Here is an edited version to match entire first part of the string till the [] braces

var data = [
    { id: 1, jobCategoryWithFromDate: "01-05 Data Specialist [valid from 2019-01-01]" },
    { id: 2, jobCategoryWithFromDate: "01-05 Support [valid from 2019-01-01]" },
    { id: 3, jobCategoryWithFromDate: "03-04 Technician [valid from 2019-01-01]" },
    { id: 4, jobCategoryWithFromDate: "05 Engineer [valid from 2019-01-01]" },
    { id: 5, jobCategoryWithFromDate: "05 Technician [valid from 2019-01-01]" },
    { id: 6, jobCategoryWithFromDate: "05 Technologist [valid from 2019-01-01]" },
    { id: 7, jobCategoryWithFromDate: "06 Engineer [valid from 2019-01-01]" },
    { id: 8, jobCategoryWithFromDate: "06-07 Sr. Technician [valid from 2019-01-01]" },
    { id: 9, jobCategoryWithFromDate: "Intern [valid from 2019-01-01]" },
    { id: 10, jobCategoryWithFromDate: "06-07 Support  [valid from 2019-01-01]" },
    { id: 11, jobCategoryWithFromDate: "06-07 Technologist [valid from 2019-01-01]" },
    { id: 12, jobCategoryWithFromDate: "07 Engineer [valid from 2019-01-01]" },
    { id: 13, jobCategoryWithFromDate: "08 Senior [valid from 2019-01-01]" },
    { id: 14, jobCategoryWithFromDate: "08-09 Support [valid from 2019-01-01]" },
    { id: 15, jobCategoryWithFromDate: "09 Senior [valid from 2019-01-01]" },
    { id: 16, jobCategoryWithFromDate: "10-11 Principal [valid from 2019-01-01]" },
    { id: 17, jobCategoryWithFromDate: "12-13 Sr. Principal [valid from 2019-01-01]" },
    { id: 18, jobCategoryWithFromDate: "14 Vice President [valid from 2019-01-01]" },
    { id: 19, jobCategoryWithFromDate: "15 President [valid from 2019-01-01]" }
];
    
function extractNameNDate(string){
  return [string.match(/[^\/]*/), string.match(/[0-9]+-[0-9]+-[0-9]+/g)];
}

var result = data.reduce((newestDates, currentItem)=>{
  const [user, date] = extractNameNDate(currentItem.jobCategoryWithFromDate);
  if (newestDates[user]) {
    // compare dates for given user
    const [storedUser, storedDate] = extractNameNDate(newestDates[user].jobCategoryWithFromDate);
    const dateDifference = new Date(storedDate) - new Date(date);
    
    if (dateDifference <= 0) newestDates[user] = currentItem;
    
  } else {
    newestDates[user]=currentItem;
  }
  return newestDates;
},{});

result = Object.values(result);

console.log(result);

Upvotes: 1

frobinsonj
frobinsonj

Reputation: 1167

I would find the latest date first and then filter the array for objects with this date. This will return only the objects with the highest date:

var data = [
  { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
  { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
  { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
  { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
  { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
  { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
  { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
  { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
  { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" }
];

/* Add new property to data objects to store the "valid from" timestamp - Avoids parsing the text twice */
data.forEach(function(element, index, array) {
  var dateText = element.jobCategoryWithFromDate.match(/\[valid from (\d{4}-\d{2}-\d{2})\]$/)[1];
  array[index].fromDateTimestamp = +(new Date(dateText));
});

/* Get the highest value (the latest date) */
var max = data.reduce(function(currentMax, value) {
  return Math.max(currentMax, value.fromDateTimestamp);
}, 0);

/* Filter the data array to only include objects with the latest date */
var newData = data.filter(function(value) {
  return value.fromDateTimestamp === max;
});

console.log(newData);

Upvotes: 1

Kobe
Kobe

Reputation: 6446

You could just use a simple sort by extracting the date with regex, then use a recursive function to check if there are multiple dates the same:

var data = [
    { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
    { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
    { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
    { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
    { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
    { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
    { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
    { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
    { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" }
];

const getDate = date => +date.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/g)[0].split('-').join('')

data = data.sort(({jobCategoryWithFromDate:date1}, {jobCategoryWithFromDate:date2}) => getDate(date2) - getDate(date1))

const getRecent = (data, i=0) => getDate(data[i].jobCategoryWithFromDate) === getDate(data[i + 1].jobCategoryWithFromDate) ? [data[i], ...getRecent(data, i+1)] : [data[i]]

getRecent(data).forEach(obj => console.log(obj))

Upvotes: 0

llccrr
llccrr

Reputation: 114

You can do it using a simple reduce, You could improve the reduce by storing the array and also the currentMaxDateTS instead of recalculate the timestamp in every iteration.

Don't hesitate if you need more explanation around this code snippet

const data = [
    { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
    { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
    { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
    { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
    { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
    { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
    { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
    { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
    { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" }
    ];

// Function returning the date string inside  [valid from 2017-05-01]
const getDateFromJobCategory = (jobCategoryWithFromDate) =>  jobCategoryWithFromDate.match(/[0-9]+-[0-9]+-[0-9]+/g);


const filteredData = data.reduce((acc, data) => {
  // Get data date in timestamp
  const dataDateString = getDateFromJobCategory(data.jobCategoryWithFromDate);
  const dataDateTS = new Date(dataDateString).getTime();
  // Get current max date in timestamp
  const currentMaxDate = getDateFromJobCategory(acc[0]);
  const currentMaxDateTS = new Date(currentMaxDate).getTime()

  return dataDateTS > currentMaxDateTS ? [data.jobCategoryWithFromDate] : dataDateTS === currentMaxDateTS ? [...acc, data.jobCategoryWithFromDate] : acc

}, ["[valid from 0001-01-01]"]);

   const finalResult = filteredData.forEach(jobCategoryWithFromDate => 
   console.log(jobCategoryWithFromDate))

Upvotes: 0

Harish
Harish

Reputation: 1901

you can apply regex to extract the date from string jobCategoryWithFromDate. then sort by date, you will get latest results on top.

var data = [
    { id: 1, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2017-05-01]" },
    { id: 2, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2018-01-01]" },
    { id: 3, jobCategoryWithFromDate: "ASSIST.. / Assistance [valid from 2019-01-01]" },
    { id: 4, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2017-05-01]" },
    { id: 5, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2018-01-01]" },
    { id: 6, jobCategoryWithFromDate: "PROF.. / Professional [valid from 2019-01-01]" },
    { id: 7, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2018-01-01]" },
    { id: 8, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2019-01-01]" },
    { id: 9, jobCategoryWithFromDate: "SEN.. / Senior [valid from 2017-05-01]" }
    ];

var result= data.map(d => ({...d, date: d.jobCategoryWithFromDate.match(/(\d{1,4}([.\-/])\d{1,2}([.\-/])\d{1,4})/g)[0]}))..sort((a, b)=> new Date(b.date) - new Date(a.date))

console.log(result)

Upvotes: 0

Related Questions