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

MongoDB聚合中生成15分钟时间块计算均值的问题求助

MongoDB聚合管道实现15分钟时间块均值计算问题

需求:构建聚合管道,计算values集合中特定变量的15分钟均值,要求生成从00:00开始、按15分钟递增的时间块(支持当前日期或指定日期)。

集合结构及示例数据

Variables集合

{
  "_id": ObjectId("65a64adb2cc01aa7c8474028"),
  "name": "Variable Name",
  "deviceId": ObjectId("65a64adb2cc01aa7c8474458")  // 设备引用ID
}

Values集合

{
     "_id": ObjectId(),
     "value": 23.45,
     "time": ISODate("2024-01-17T11:09:35.681Z"),
     "metaField": {"varId": ObjectId("65a64adb2cc01aa7c8474028")} // 变量引用ID
}

目标输出格式

{
    "Date": "2024-01-17",
    "Segment": "00:00-00:15",
    "Block": 1,
    "Average": 23.45,
    "VarId": ObjectId("65a64adb2cc01aa7c8474028")
}

当前聚合查询

[
  {
    "$match": {
      "metaField.varId": ObjectId('65a64adb2cc01aa7c8474028'),
      "time": {
        "$gte": new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()),
        "$lt": new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() + 1)
      }
    }
  },
  {
    "$addFields": {
      "bucket": {
        "$floor": {
          "$divide": [{ "$subtract": [{ "$minute": "$time" }, 1] }, 15]
        }
      }
    }
  },
  {
    "$group": {
      "_id": { "bucket": "$bucket" },
      "count": { "$sum": 1 },
      "sumValue": { "$sum": "$value" }
    }
  },
  {
    "$project": {
      "_id": 0,
      "segment": {
        "$concat": [
          { "$substr": [{ "$multiply": ["$_id.bucket", 15] }, 0, -1] },
          ":00-",
          { "$substr": [{ "$add": [{ "$multiply": ["$_id.bucket", 15] }, 15] }, 0, -1] }
        ]
      },
      "block": { "$add": ["$_id.bucket", 1] },
      "average": { "$divide": ["$sumValue", "$count"] },
      "varId": "$metaField.varId"
    }
  }
]

遇到的问题

时间块未按预期递增,结果与目标输出不符——核心原因是原逻辑仅基于分钟计算bucket,未考虑小时因素,导致跨小时的15分钟块会重复bucket编号,且时间格式化未补前导零,输出格式不规范。

优化后的聚合管道

[
  {
    "$match": {
      "metaField.varId": ObjectId('65a64adb2cc01aa7c8474028'),
      "time": {
        "$gte": ISODate("2024-01-17T00:00:00Z"), // 指定日期,或保留原动态生成逻辑
        "$lt": ISODate("2024-01-18T00:00:00Z")
      }
    }
  },
  {
    "$addFields": {
      // 提取日期字符串,用于输出
      "dateStr": { "$dateToString": { "format": "%Y-%m-%d", "date": "$time" } },
      // 计算当天的总分钟数(小时*60 + 分钟),再除以15得到唯一的bucket编号
      "totalMinutes": { "$add": [{ "$multiply": [{ "$hour": "$time" }, 60] }, { "$minute": "$time" }] },
      "bucket": { "$floor": { "$divide": ["$totalMinutes", 15] } }
    }
  },
  {
    "$group": {
      "_id": {
        "bucket": "$bucket",
        "varId": "$metaField.varId",
        "date": "$dateStr"
      },
      "count": { "$sum": 1 },
      "sumValue": { "$sum": "$value" }
    }
  },
  {
    "$project": {
      "_id": 0,
      "Date": "$_id.date",
      "VarId": "$_id.varId",
      "Block": { "$add": ["$_id.bucket", 1] },
      // 计算时间块起始的小时和分钟,补前导零
      "startHour": { "$toString": { "$floor": { "$divide": [{ "$multiply": ["$_id.bucket", 15] }, 60] } } },
      "startMinute": { "$toString": { "$mod": [{ "$multiply": ["$_id.bucket", 15] }, 60] } },
      "endHour": { "$toString": { "$floor": { "$divide": [{ "$add": [{ "$multiply": ["$_id.bucket", 15] }, 15] }, 60] } } },
      "endMinute": { "$toString": { "$mod": [{ "$add": [{ "$multiply": ["$_id.bucket", 15] }, 15] }, 60] } },
      "Average": { "$divide": ["$sumValue", "$count"] }
    }
  },
  {
    "$addFields": {
      // 格式化Segment字段,补前导零确保两位格式
      "Segment": {
        "$concat": [
          { "$cond": [{ "$lt": [{ "$strLenCP": "$startHour" }, 2] }, "0", "" ] }, "$startHour", ":",
          { "$cond": [{ "$lt": [{ "$strLenCP": "$startMinute" }, 2] }, "0", "" ] }, "$startMinute", "-",
          { "$cond": [{ "$lt": [{ "$strLenCP": "$endHour" }, 2] }, "0", "" ] }, "$endHour", ":",
          { "$cond": [{ "$lt": [{ "$strLenCP": "$endMinute" }, 2] }, "0", "" ] }, "$endMinute"
        ]
      }
    }
  },
  {
    // 移除中间计算字段,保留目标输出字段
    "$project": {
      "Date": 1,
      "Segment": 1,
      "Block": 1,
      "Average": 1,
      "VarId": 1
    }
  },
  {
    // 按Block升序排列,确保时间块顺序正确
    "$sort": { "Block": 1 }
  }
]

关键改进点

  1. Bucket计算逻辑修正:基于当天总分钟数计算bucket,确保每个15分钟块(从00:00开始)对应唯一的bucket编号,避免跨小时重复。
  2. 时间格式化补零:通过$cond和$strLenCP判断小时/分钟的字符串长度,补前导零,保证输出格式为HH:MM-HH:MM。
  3. 保留必要字段:分组时包含日期和变量ID,确保输出符合目标格式;最后按Block升序排列,保证结果顺序正确。
  4. 灵活日期范围:$match阶段可替换为动态生成当前日期的逻辑(保留原代码的new Date()写法),也可指定固定日期。

内容的提问来源于stack exchange,提问作者anonymous_33008899

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:53:14