JavaScript中为对象数组的嵌套数组补充缺失日期对象
问题需求
处理后端返回的对象数组,将每个对象中嵌套的hours数组内的日期与指定日期数组compDates比对,若hours中不存在对应日期,则添加count: 0的对象。
原始数据
[{ _id: "6205a8313fe12d6b4ec354c4", fullName: "Johnny Cochrane", contracts: { type: "Quarterly", hours: 120, }, client: "6205a8313fe12d6b4ec354c4", hours: [{ date: "2023-5", count: 6, }, { date: "2023-6", count: 2, }], }, { _id: "6217c1b73fe12d6b4ec3550e", fullName: "Sheila Thompson", contracts: { type: "Quarterly", hours: 140, }, client: "6217c1b73fe12d6b4ec3550e", hours: [{ date: "2023-4", count: 5.5, }, { date: "2023-6", count: 2, }], }]
生成对比日期的代码
const qtrs = [{qtr: 1, mths: [1,2,3]}, {qtr: 2, mths: [4,5,6]}, {qtr: 3, mths: [7,8,9]}, {qtr: 4, mths: [10,11,12]} ] const currentMth = new Date().getMonth() + 1 const currentQtr = qtrs.filter(({mths}) => mths.includes(currentMth)) const compDates = currentQtr[0].mths.map(i => new Date(new Date(new Date().setMonth(i)).setHours(0, 0, 0, 0)).toISOString())
尝试过的处理代码
const adjust = data.forEach(i => { i.hours.forEach(item => { console.log("item1: ",item) const interim = new Date(item.date).getMonth() + 1 console.log(interim) item.date = new Date(new Date(new Date().setMonth(interim)).setHours(0, 0, 0, 0)).toISOString() console.log(item.date) //Steps I've tried- 1st: cursor = 0 Object.entries(item).map(obj => {console.log(obj); compDates[cursor] && compDates[cursor] == obj.date ? {...obj} :{count: 0, date: obj.date, total: obj.total}}); //2nd try Object.values(item).map(x => (compDates.find(y => y === x.date) ? {...x}: {count: 0, date: x.date, total: x.total})) //3rd if (compDates.find(y => y === item.date)) { item = item } else { item = {count: 0, date: item.date, total: item.total} } })})
期望输出
对比日期示例
["2023-05-16T07:00:00.258Z", "2023-06-16T07:00:00.258Z", "2023-07-16T07:00:00.258Z"]
处理后的数据
[{ _id: "6205a8313fe12d6b4ec354c4", fullName: "Johnny Cochrane", contracts: { type: "Quarterly", hours: 120, }, client: "6205a8313fe12d6b4ec354c4", hours: [{ date: "2023-4", // 比对阶段无需改回ISO日期格式 count: 0, }, { date: "2023-5", count: 6, }, { date: "2023-6", count: 2, }], }, { _id: "6217c1b73fe12d6b4ec3550e", fullName: "Sheila Thompson", contracts: { type: "Quarterly", hours: 140, }, client: "6217c1b73fe12d6b4ec3550e", hours: [{ date: "2023-4", count: 5.5, }, { date: "2023-5", // 同样无需改回原格式 count: 0, }, { date: "2023-6", count: 2, }], }]
解决方案
你之前的尝试只在修改原有hours项,没遍历compDates补全缺失项,而且原compDates生成逻辑有问题(重复修改同一个Date对象导致日期错误)。以下是可行的处理方案:
修复并优化的代码
// 修复compDates生成逻辑,避免日期对象污染 const qtrs = [{qtr: 1, mths: [1,2,3]}, {qtr: 2, mths: [4,5,6]}, {qtr: 3, mths: [7,8,9]}, {qtr: 4, mths: [10,11,12]} ] const currentYear = new Date().getFullYear(); const currentMth = new Date().getMonth() + 1; const currentQtr = qtrs.find(({mths}) => mths.includes(currentMth)); // 用find更高效,仅返回匹配的季度 // 生成每个季度月份的当月第一天ISO格式日期 const compDates = currentQtr.mths.map(month => { const date = new Date(currentYear, month - 1, 1); // 月份从0开始,需减1 date.setHours(0, 0, 0, 0); return date.toISOString(); }); // 处理数据的核心函数 const processData = (data) => { return data.map(person => { // 把已有hours转成Map,key为ISO日期,value为count,方便快速查找 const existingHoursMap = new Map( person.hours.map(item => { // 将原始"YYYY-M"格式转成ISO格式 const [year, month] = item.date.split('-'); const date = new Date(parseInt(year), parseInt(month) - 1, 1); date.setHours(0, 0, 0, 0); return [date.toISOString(), item.count]; }) ); // 遍历compDates生成完整的hours数组,缺失的日期补count:0 const updatedHours = compDates.map(date => ({ // 若需要转回"YYYY-M"格式,替换下面的date字段: // date: `${new Date(date).getFullYear()}-${new Date(date).getMonth() + 1}`, date: date, count: existingHoursMap.get(date) || 0 })); return { ...person, hours: updatedHours }; }); }; // 使用示例:传入你的原始数据 const processedResult = processData(原始数据); console.log(processedResult);
代码说明
- 修复日期生成逻辑:原代码多次调用
setMonth会修改同一个Date对象,导致后续月份计算错误,改用创建新Date对象的方式生成正确的对比日期; - 用Map优化查找效率:将已有日期和count存入Map,比对时时间复杂度从O(n)降到O(1);
- 补全缺失日期:直接遍历
compDates生成完整的hours数组,确保每个对比日期都存在,缺失项自动补count:0; - 格式灵活切换:保留了日期格式转换的选项,可根据需求选择ISO格式或原始的"YYYY-M"格式。
内容的提问来源于stack exchange,提问作者Jowz
相关产品推荐
相关产品推荐

