MongoDB按date、hour分组统计唯一sessionId数量的查询请求
解决方案:MongoDB按日期+小时统计唯一会话数
没问题,我帮你写出完全匹配需求的MongoDB聚合查询,分为两种场景供你选择:
场景1:只统计存在数据的小时(无数据的小时不显示)
这个版本会直接根据你集合中存在的date和hour分组统计,没有记录的小时不会出现在结果中:
db.yourCollectionName.aggregate([ // 按日期和小时分组,统计该组内唯一sessionId的数量 { $group: { _id: { date: "$date", hour: "$hour" }, uniqueSessions: { $size: { $addToSet: "$sessionId" } } } }, // 按日期聚合,整理每个日期下的小时统计数据为键值对数组 { $group: { _id: "$_id.date", hourData: { $push: { k: "$_id.hour", v: "$uniqueSessions" } } } }, // 将日期作为键,小时统计对象作为值,生成键值对结构 { $project: { _id: 0, data: { k: "$_id", v: { $arrayToObject: "$hourData" } } } }, // 转换为最终的对象格式输出 { $replaceRoot: { newRoot: { $arrayToObject: "$data" } } } ])
场景2:补全所有24小时(无数据的小时显示0)
如果需要像你示例中那样,即使某个小时没有会话记录也显示0,可以用这个版本,会自动补全00-23所有小时:
db.yourCollectionName.aggregate([ // 基础统计:按日期+小时统计唯一会话数 { $group: { _id: { date: "$date", hour: "$hour" }, uniqueSessions: { $size: { $addToSet: "$sessionId" } } } }, // 按日期聚合,收集该日期下的所有小时统计数据 { $group: { _id: "$_id.date", stats: { $push: { hour: "$_id.hour", count: "$uniqueSessions" } } } }, // 生成0-23的数字小时数组 { $addFields: { allHours: { $range: [0, 24] } } }, // 将数字小时转换为两位字符串格式(比如0→"00",5→"05") { $addFields: { allHours: { $map: { input: "$allHours", as: "h", in: { $toString: { $concat: [ { $substr: ["0", 0, { $subtract: [2, { $strLenCP: { $toString: "$$h" } }] }] }, { $toString: "$$h" } ] } } } } } }, // 左连接所有小时和统计数据,无数据的小时填充为0 { $addFields: { hourData: { $map: { input: "$allHours", as: "hour", in: { k: "$$hour", v: { $ifNull: [ { $arrayElemAt: ["$stats.count", { $indexOfArray: ["$stats.hour", "$$hour"] }] }, 0 ] } } } } } }, // 构建日期到小时统计对象的键值对 { $project: { _id: 0, data: { k: "$_id", v: { $arrayToObject: "$hourData" } } } }, // 转换为最终的目标格式 { $replaceRoot: { newRoot: { $arrayToObject: "$data" } } } ])
关键步骤说明
$addToSet+$size:确保统计的是唯一的sessionId数量,而不是该小时内的总记录数。$arrayToObject:将数组形式的键值对转换为对象结构,完美匹配你需要的输出格式。- 场景2中的
$range和$map:用于生成并格式化所有24小时,保证结果的完整性。
内容的提问来源于stack exchange,提问作者Tony Mathew
相关产品推荐
相关产品推荐

