Home > Back-end >  Getting Missing Months
Getting Missing Months

Time:05-07

I am working on a project where I am trying to chart the number of monthly order that I have received. My current data for monthlyOrder is:

[
  {
    _id: { month: 12, year: 2021 },
    year: 2021,
    month: 'December',
    orders: 1
  },
  {
    _id: { month: 4, year: 2022 },
    year: 2022,
    month: 'April',
    orders: 31
  },
  {
    _id: { month: 5, year: 2022 },
    year: 2022,
    month: 'May',
    orders: 2
  }
]

I would like to have an array with all missing months with orders: 0, so that all months since the first month/date are included in the chart.

I have attempted to do this by:

let startYear = monthlyOrders[0]._id.year;
        let startMonth = monthlyOrders[0]._id.month;
        let endYear = monthlyOrders[monthlyOrders.length - 1]._id.year;
        let endMonth = monthlyOrders[monthlyOrders.length - 1]._id.month;
        let months = [
            'January',
            'February',
            'March',
            'April',
            'May',
            'June',
            'July',
            'August',
            'September',
            'October',
            'November',
            'December',
        ];

function getMonthlys () {
    if (startYear === endYear) {
      if (startMonth === endMonth) {
       let date = {
           month: startMonth,
           year: startYear,
       }
       if (startMonth < endMonth) {
          let months = 1;
             while (months <= endMonth) {
              months = months   1;
              }
           let date = 
           {
               month: months,
               year: startYear,
           }
       }
    }
    }
}

However, this is probably not the best way to do this, and I am not sure how to deal with dates where startYear < endYear, but startMonth === endMonth.

Additionally, to deal with adding 0 for orders when one doesn't exist I have tried to do this:

 let monthsObj = [];
        for (let i = startYear; i <= endYear; i  ) {
            for (let j = startMonth; j <= 12; j  ) {
                if (!(j > endMonth && i === endYear)) {
                    let obj = {
                        month: j,
                        year: i,
                    };
                    monthsObj.push(obj);
                }
            }
        }

        
        for (let dateVal of monthsObj) {
            let isInArray = false;

            for (let dayVal of monthlyOrders) {
                

                if (dayVal._id.year == dateVal.year && dayVal._id.month == dateVal.month) {
                    isInArray = true;
                }
            }
            if (isInArray === false) {
                let obj = {
                    month: dateVal.month,
                    year: dateVal.year,
                };
                monthlyOrders.push({ _id: obj, year: dateVal.year, month: months[dateVal.month - 1], orders: 0 });
               
            }
        }

I would really appreciate any suggestion or on how to get the:

[
  {
    _id: { month: 12, year: 2021 },
    year: 2021,
    month: 'December',
    orders: 1
  },
 {
    _id: { month: 1, year: 2022 },
    year: 2022,
    month: 'January',
    orders: 0
  },
 {
    _id: { month: 2, year: 2022 },
    year: 2022,
    month: 'February',
    orders: 0
  },
{
    _id: { month: 3, year: 2022 },
    year: 2022,
    month: 'March',
    orders: 0
  },

  {
    _id: { month: 4, year: 2022 },
    year: 2022,
    month: 'April',
    orders: 31
  },
  {
    _id: { month: 5, year: 2022 },
    year: 2022,
    month: 'May',
    orders: 2
  }
]

array that I need.

CodePudding user response:

However, this is probably not the best way to do this, and I am not sure how to deal with dates where startYear < endYear, but startMonth === endMonth.

I think an easier approach would be for each iteration of the loop to add a single object to the output array, along with keeping track of the current index of the input array being iterated over. If, on an iteration, the object in the input array has a matching month and year, push it - otherwise, push the placeholder object (with the one-indexed month accounted for). Then, if index being iterated over is the final one in the original array, break - otherwise, increment the month and then (if needed) the year.

const monthlyOrders=[{_id:{month:12,year:2021},year:2021,month:"December",orders:1},{_id:{month:4,year:2022},year:2022,month:"April",orders:31},{_id:{month:5,year:2022},year:2022,month:"May",orders:2}];
const months=["January","February","March","April","May","June","July","August","September","October","November","December"];

let { year, month } = monthlyOrders[0]._id;
const endYear = monthlyOrders[monthlyOrders.length - 1]._id.year;
const endMonth = monthlyOrders[monthlyOrders.length - 1]._id.month;

const output = [];
let monthlyOrdersIndex = 0;
while (monthlyOrdersIndex !== monthlyOrders.length) {
    // If the month/year we're on exists in the original array, use it:
    if (year === monthlyOrders[monthlyOrdersIndex]._id.year && month === monthlyOrders[monthlyOrdersIndex]._id.month) {
        output.push(monthlyOrders[monthlyOrdersIndex]);
        monthlyOrdersIndex  ;
    } else {
        output.push({
            _id: { month, year },
            year: year,
            month: months[month - 1],
            orders: 0
        });
    }
    month = month === 12 ? 1 : month   1;
    if (month === 1) year  ;
}
console.log(output);

CodePudding user response:

You can use the javascript Date object to compare an step through the months. Your code, I couldn't tell what it was doing with each month, but this adds them to an array and returns it.


let startYear = 2021;
        let startMonth = 6;
        let endYear = 2023;
        let endMonth = 2;
        let months = [
            'January',
            'February',
            'March',
            'April',
            'May',
            'June',
            'July',
            'August',
            'September',
            'October',
            'November',
            'December',
        ];

function getMonthlys () {
  var list = []
  var startdate = new Date(startYear, startMonth, 1)
  var enddate = new Date(endYear, endMonth, 1)
  while (startdate < enddate) {
    list.push({
        month: startdate.getMonth(),
      year: startdate.getFullYear()
    })
    startdate.setMonth(startdate.getMonth()   1) 
  }
  return list
}

var allmonths = getMonthlys();



Then you just need to find the data for each one of those months

// for each month, find a match
var orders = allmonths.map( function(month) {

   var match = datasrc.find(function(entry) {
        return entry._id.month == month.month && entry._id.year == month.year
   });
   if (match) {
     return match
   }
   else {
     return {
       _id: month,
       month: months[month.month-1],
       year: month.year,
       orders: 0
     }
   }

})

You can see in this fiddle https://jsfiddle.net/myt19j30/1/

  • Related