You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 11:10:40