Home > Back-end >  Filter and map data according to the interval of the weeks of the month
Filter and map data according to the interval of the weeks of the month

Time:12-02

I have an array of objects, each object has four properties (id, start, end and amount).

Then from this data I create a new array of objects with the following properties: date, duration and amount. The date is the date of the timestamp of the start property, duration is the time in minutes between start timestamp and end timestamp.

Then I created two variables, one is from the selected month and the other is from the selected year. Then filter the array dates according to the selected month and year. For example, if month 11 is selected, I would only want objects whose dates are from month 11. And the same applies to the year. The final result turns out to be a list of days according to the selected month and year.

const arrayOfDates = [
    {
        id: 1,
        start: '2021-12-01T12:10:56 0000',
        end: '2021-12-01T12:00:56 0000',
        amount: 10
    },
    {
        id: 2,
        start: '2021-12-03T11:10:56 0000',
        end: '2021-12-03T12:45:56 0000',
        amount: 4
    },
    {
        id: 3,
        start: '2021-12-07T09:10:56 0000',
        end: '2021-12-07T09:25:56 0000',
        amount: 8
    },
    {
        id: 4,
        start: '2021-11-24T11:10:56 0000',
        end: '2021-11-24T11:25:56 0000',
        amount: 8
    }
]

const selectedMonth = 12
const selectedYear = 2021

const mapped = arrayOfDates.map((el) => ({
    date: new Date(el.start).toLocaleDateString('en-CA'),
    duration: new Date(new Date(el.end).getTime() - new Date(el.start).getTime()).getMinutes(),
    amount: el.amount
}))

const filteredBySelectedDate = mapped.filter((el) => {
    var [year, month] = el.date.split('-')
    return selectedMonth ===  month && selectedYear ===  year;
})

const mappedByDays = filteredBySelectedDate

However, in addition to having the elements of the array listed by day (which is the result I currently have). I would like to use the filteredBySelectedDate array to filter by weeks. In other words, I wanted to group the elements of the array according to the range of weeks of the month. An array like this:

const mappedByWeeks = [
    {
        interval: '12/01 - 12/04',
        duration: 85,
        amount: 14
    },
    {
        interval: '12/05 - 12/11',
        duration: 15,
        amount: 8
    }
]

CodePudding user response:

This can be accomplished in a few steps. First by building up the known start/end days for each week of the month (weekTransitionDays). Secondly a way of identifying which week an entry belongs to (getWeekIndex). And lastly a means of collapsing entries together for the same week (groupByWeek).

const arrayOfDates = [{
    id: 1,
    start: '2021-12-01T12:10:56 0000',
    end: '2021-12-01T12:00:56 0000',
    amount: 10
  },
  {
    id: 2,
    start: '2021-12-03T11:10:56 0000',
    end: '2021-12-03T12:45:56 0000',
    amount: 4
  },
  {
    id: 3,
    start: '2021-12-07T09:10:56 0000',
    end: '2021-12-07T09:25:56 0000',
    amount: 8
  },
  {
    id: 4,
    start: '2021-11-24T11:10:56 0000',
    end: '2021-11-24T11:25:56 0000',
    amount: 8
  }
];

const selectedMonth = 12;
const selectedYear = 2021;

const weekTransitionDays = [];
const firstDayOfMonth = (new Date(selectedYear, selectedMonth - 1, 1)).getDay();
const daysInMonth = (new Date(selectedYear, selectedMonth, 0)).getDate();
let start = 1;
if (firstDayOfMonth !== 0) {
  let end = start   6 - firstDayOfMonth;
  weekTransitionDays.push([start, end]);
  start = end;
}
while (start < daysInMonth) {
  let end;
  if (start   1 < daysInMonth) {
    start  ;
  } else {
    break;
  }
  if (start   6 < daysInMonth) {
    end = start   6;
  } else {
    break;
  }
  weekTransitionDays.push([start, end]);
  start = end;
}
if (weekTransitionDays.at(-1)[1] !== daysInMonth) {
  weekTransitionDays.push([start, daysInMonth]);
}

const getWeekIndex = entry => {
  const entryStart = new Date(entry.start).getDate();
  for (let i = 0; i < weekTransitionDays.length; i  ) {
    if (weekTransitionDays[i][0] <= entryStart && entryStart <= weekTransitionDays[i][1]) {
      return i;
    }
  }
};

const mapped = arrayOfDates.map((el) => ({
  date: new Date(el.start).toLocaleDateString('en-CA'),
  duration: new Date(new Date(el.end).getTime() - new Date(el.start).getTime()).getMinutes(),
  weekIndex: getWeekIndex(el),
  amount: el.amount
}));

const filteredBySelectedDate = mapped.filter((el) => {
  var [year, month] = el.date.split('-');
  return selectedMonth ===  month && selectedYear ===  year;
});

const groupByWeek = () => {
  const obj = {};
  filteredBySelectedDate.forEach(entry => {
    if (!obj.hasOwnProperty(entry.weekIndex)) {
      let [start, end] = weekTransitionDays[entry.weekIndex];
      if (start < 10) {
        start = "0"   start;
      }
      if (end < 10) {
        end = "0"   end;
      }
      start = selectedMonth   "/"   start;
      end = selectedMonth   "/"   end;
      obj[entry.weekIndex] = {
        interval: start   ' - '   end,
        duration: 0,
        amount: 0
      };
    }
    obj[entry.weekIndex].duration  = entry.duration;
    obj[entry.weekIndex].amount  = entry.amount;
  });
  return Object.values(obj);
};

const mappedByDays = filteredBySelectedDate;
const groupedByWeek = groupByWeek(mapped);

console.log(groupedByWeek);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related