Skip to content
Advertisement

Getting Missing Months

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.

Advertisement

Answer

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);
Advertisement