MongoDB聚合:为时段过滤字段添加平均值字段的实现问询
MongoDB聚合查询:按时段统计点击量并计算平均值
假设你的用户集合结构如下:
{ "userId": "user123", "data": [ { "date": ISODate("2024-05-01T00:00:00Z"), "hits": 15 }, { "date": ISODate("2024-05-10T00:00:00Z"), "hits": 22 }, // 更多历史数据... ] }
可以通过以下聚合管道实现需求:先匹配目标用户,再分别生成三个时段的过滤数据和对应点击量平均值,最终输出包含avg和data子字段的结构。
基础实现版本
db.users.aggregate([ // 第一步:匹配指定用户ID { $match: { userId: "目标用户ID" } // 替换为实际要查询的userId }, // 第二步:生成三个时段的统计结果 { $project: { last_seven_days: { // 筛选近7天的点击数据 data: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 7 * 24 * 60 * 60 * 1000] }] } } }, // 计算近7天点击量平均值 avg: { $avg: { $map: { input: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 7 * 24 * 60 * 60 * 1000] }] } } }, as: "item", in: "$$item.hits" } } } }, last_month: { data: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 30 * 24 * 60 * 60 * 1000] }] } } }, avg: { $avg: { $map: { input: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 30 * 24 * 60 * 60 * 1000] }] } } }, as: "item", in: "$$item.hits" } } } }, last_year: { data: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 365 * 24 * 60 * 60 * 1000] }] } } }, avg: { $avg: { $map: { input: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 365 * 24 * 60 * 60 * 1000] }] } } }, as: "item", in: "$$item.hits" } } } } } } ])
优化高效版本
如果data数组数据量较大,基础版本重复执行$filter会浪费资源。可以先通过$addFields生成临时过滤结果,再复用计算平均值,减少重复运算:
db.users.aggregate([ { $match: { userId: "目标用户ID" } }, // 先一次性生成三个时段的过滤数据作为临时字段 { $addFields: { _temp_last7: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 7*24*60*60*1000] }] } } }, _temp_last30: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 30*24*60*60*1000] }] } } }, _temp_last365: { $filter: { input: "$data", cond: { $gte: ["$$this.date", { $subtract: [new Date(), 365*24*60*60*1000] }] } } } } }, // 基于临时字段生成最终结果并清理临时数据 { $project: { last_seven_days: { data: "$_temp_last7", avg: { $avg: "$_temp_last7.hits" } }, last_month: { data: "$_temp_last30", avg: { $avg: "$_temp_last30.hits" } }, last_year: { data: "$_temp_last365", avg: { $avg: "$_temp_last365.hits" } }, _temp_last7: 0, _temp_last30: 0, _temp_last365: 0 } } ])
关键细节说明
- 时间范围计算:通过
$subtract将当前时间(new Date())减去对应毫秒数,得到时段起始时间(比如7天=72460601000毫秒)。 - 空值处理:如果时段内无数据,
$avg会返回null,若需要默认值(比如0),可以用$ifNull包裹计算逻辑:$ifNull: [{$avg: "$_temp_last7.hits"}, 0]。
内容的提问来源于stack exchange,提问作者Sai Krishna
相关产品推荐
相关产品推荐

