如何使用moment和lodash按对象字段分组并按日期范围统计计数?
使用Moment.js和Lodash按字段分组并按日期统计计数
咱们先从基础的按对象字段分组+日期计数需求开始,再一步步拆解你遇到的复杂场景。
一、基础场景:按指定字段分组,统计每组内各日期的出现次数
假设你有如下格式的初始数据:
const rawData = [ { group: 'Group1', date: '2024-05-01' }, { group: 'Group1', date: '2024-05-01' }, { group: 'Group2', date: '2024-05-02' }, { group: 'Group1', date: '2024-05-03' }, { group: 'Group2', date: '2024-05-03' }, { group: 'Group2', date: '2024-05-03' } ];
实现步骤:
- 用Lodash的
_.groupBy按group字段分组 - 对每个分组,用
_.countBy结合Moment.js格式化后的日期统计次数
代码示例:
// 第一步:按group字段分组 const groupedByGroup = _.groupBy(rawData, 'group'); // 第二步:转换为带日期计数的结构 const basicResult = _.mapValues(groupedByGroup, (items) => { // 按格式化后的日期统计出现次数 const dateCounts = _.countBy(items, (item) => moment(item.date).format('YYYY-MM-DD')); return { totalItems: items.length, // 可选:组内总条目数 dateCounts: dateCounts }; }); console.log(basicResult);
输出结果会是:
{ "Group1": { "totalItems": 3, "dateCounts": { "2024-05-01": 2, "2024-05-03": 1 } }, "Group2": { "totalItems": 3, "dateCounts": { "2024-05-02": 1, "2024-05-03": 2 } } }
二、复杂场景:分组后生成完整日期范围的计数(含无数据日期)
针对你提到的「生成startDate到endDate的完整日期范围,每个日期对应计数(无匹配则为0)」的需求,我们需要先生成完整的日期序列,再补全每个分组的日期计数。
1. 先写一个生成日期范围的工具函数
用Moment.js遍历生成指定区间内的所有日期:
function getDateRange(startDateStr, endDateStr) { const dates = []; let currentDate = moment(startDateStr); const endDate = moment(endDateStr); // 循环生成日期,直到超过结束日期 while (currentDate.isSameOrBefore(endDate)) { dates.push(currentDate.format('YYYY-MM-DD')); currentDate.add(1, 'day'); } return dates; }
2. 处理分组并生成目标结构
假设你的日期范围是2024-05-01到2024-05-04,代码示例:
const startDate = '2024-05-01'; const endDate = '2024-05-04'; // 生成完整日期范围数组 const fullDateRange = getDateRange(startDate, endDate); // 第一步:按group字段分组 const groupedData = _.groupBy(rawData, 'group'); // 第二步:转换为包含完整日期计数的结构 const complexResult = _.mapValues(groupedData, (items) => { // 先统计现有日期的计数 const existingDateCounts = _.countBy(items, (item) => moment(item.date).format('YYYY-MM-DD')); // 构建dates字段:遍历完整日期范围,无匹配则设为0 const dateCounts = _.fromPairs( fullDateRange.map(date => [date, existingDateCounts[date] || 0]) ); return { dates: dateCounts, total: items.length // 可选:组内总条目数 }; }); console.log(complexResult);
输出结果会包含完整日期范围,即使某日期没有匹配数据也会显示0:
{ "Group1": { "dates": { "2024-05-01": 2, "2024-05-02": 0, "2024-05-03": 1, "2024-05-04": 0 }, "total": 3 }, "Group2": { "dates": { "2024-05-01": 0, "2024-05-02": 1, "2024-05-03": 2, "2024-05-04": 0 }, "total": 3 } }
注意事项
- 确保你的日期格式能被Moment.js正确解析,如果是时间戳、ISO字符串等特殊格式,需要在
moment()中指定格式,比如moment(item.date, 'YYYY/MM/DD') - 如果日期范围非常大(比如跨年),可以考虑优化日期生成逻辑,但一般业务场景下上述方法足够高效
- Lodash的
_.fromPairs方法用于将二维数组转换为键值对对象,非常适合构建日期计数结构
内容的提问来源于stack exchange,提问作者Ventrove
相关产品推荐
相关产品推荐

