如何将事件对象数组归约为按Programme分类的单一统计结果对象
如何将多事件统计合并为单一按programme分组的统计对象?
我来帮你重构代码,把原来的两个Map合并成符合你需求的单一统计对象。核心思路是用一个对象来按programme分组,每个分组下维护所有事件类型的计数,同时保留你原来的点击事件时间校验逻辑。
重构后的完整代码
// 初始化统计对象和投递时间映射(用于校验点击事件的时间范围) const stats = {}; const deliverDates = {}; emails.forEach((record) => { const data = JSON.parse(record.data); const programme = data.programme; // 根据你的事件结构,从解析后的数据中获取programme const eventName = data.name; // 确保当前programme的统计项已初始化,避免后续计数时出现undefined if (!stats[programme]) { stats[programme] = { delivered: 0, failed: 0, expired: 0, click: 0 }; } // 用switch处理不同事件类型,比多个if更清晰易维护 switch (eventName) { case 'email.delivered': { const messageId = data.payload.id; // 只记录第一次投递的时间(和你原来的逻辑一致) if (!deliverDates[messageId]) { deliverDates[messageId] = record.timestamp; } stats[programme].delivered += 1; break; } case 'email.failed': { stats[programme].failed += 1; break; } case 'email.expired': { stats[programme].expired += 1; break; } case 'email.click': { const messageId = data.payload.correlation?.messageId; if (messageId) { const deliveryTimestamp = deliverDates[messageId]; if (deliveryTimestamp) { const deliveryDate = new Date(deliveryTimestamp); // 只统计14天内投递的邮件对应的点击(和你原来的时间阈值一致) if (deliveryDate.getTime() > Date.now() - 1209600000) { stats[programme].click += 1; } } } break; } default: // 可选:处理未知事件类型,方便调试 console.warn(`Encountered unknown event type: ${eventName}`); } }); // 最终stats就是你需要的格式 console.log(stats);
代码说明
- 单一统计对象:用
stats对象替代原来的两个Map,直接以programme为键,每个键对应的值包含所有事件类型的计数,完全匹配你期望的输出格式。 - 统一初始化:在处理每个programme的第一个事件时,自动初始化该分组下的所有计数为0,避免出现缺失字段的情况。
- 清晰的事件处理:用
switch语句替代多个if判断,后续添加新事件类型时只需新增case即可,代码可读性和可维护性更强。 - 保留核心逻辑:完全保留了你原来的点击事件时间校验逻辑,确保只统计14天内投递的邮件产生的点击。
- 容错处理:增加了对未知事件类型的警告,方便排查数据异常。
注意事项
如果你原来的programme字段是在record而非data中(比如你的示例代码里有const programme = record?.programme),只需把const programme = data.programme改成const programme = record.programme即可。
内容的提问来源于stack exchange,提问作者TTBox
相关产品推荐
相关产品推荐

