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

求助:按名称和时间间隔聚合MongoDB商品价格数据

MongoDB聚合查询:按商品获取不同时间点的价格

我明白你找了好几天都没搞定这个查询,别着急,咱们一步步来解决这个问题。

首先看你手里的原始数据,是按商品分组的时间序列价格记录:

[
  { name: 'apple', date: ISODate("2018-01-04T10:00:00.000Z"), price: 100 },
  { name: 'apple', date: ISODate("2018-01-04T10:01:00.000Z"), price: 101 },
  { name: 'apple', date: ISODate("2018-01-04T10:02:00.000Z"), price: 102 },
  { name: 'apple', date: ISODate("2018-01-04T10:03:00.000Z"), price: 103 },
  { name: 'apple', date: ISODate("2018-01-04T10:04:00.000Z"), price: 102 },
  { name: 'apple', date: ISODate("2018-01-04T10:05:00.000Z"), price: 104 },
  { name: 'cherry', date: ISODate("2018-01-04T10:00:00.000Z"), price: 53 },
  { name: 'cherry', date: ISODate("2018-01-04T10:01:00.000Z"), price: 55 },
  { name: 'cherry', date: ISODate("2018-01-04T10:02:00.000Z"), price: 51 },
  { name: 'cherry', date: ISODate("2018-01-04T10:03:00.000Z"), price: 51 },
  { name: 'cherry', date: ISODate("2018-01-04T10:04:00.000Z"), price: 50 },
  { name: 'cherry', date: ISODate("2018-01-04T10:05:00.000Z"), price: 52 },
  { name: 'melon', date: ISODate("2018-01-04T10:00:00.000Z"), price: 133 },
  { name: 'melon', date: ISODate("2018-01-04T10:01:00.000Z"), price: 132 },
  { name: 'melon', date: ISODate("2018-01-04T10:02:00.000Z"), price: 136 },
  { name: 'melon', date: ISODate("2018-01-04T10:03:00.000Z"), price: 137 },
  { name: 'melon', date: ISODate("2018-01-04T10:04:00.000Z"), price: 138 },
  { name: 'melon', date: ISODate("2018-01-04T10:05:00.000Z"), price: 140 }
]

你想要的结果是每个商品一行,包含最新价格、1分钟前的价格、5分钟前的价格:

[
  {name: 'apple', price_last: 104, price_1m_ago: 102, price_5m_ago: 100},
  {name: 'cherry', price_last: 52, price_1m_ago: 50, price_5m_ago: 53},
  {name: 'melon', price_last: 140, price_1m_ago: 138, price_5m_ago: 133}
]

你之前尝试了基础的$group只拿到了最新价格,确实还不够,咱们需要扩展聚合管道来匹配不同时间点的价格。

解决方案:完整聚合查询

这里给你写好完整的聚合语句,我会一步步解释每个阶段的作用:

food.aggregate([
  // 第一步:按商品分组,把每个商品的所有价格记录按日期排序后存到数组里
  {
    $group: {
      _id: "$name",
      priceHistory: {
        $push: {
          date: "$date",
          price: "$price"
        }
      }
    }
  },
  // 第二步:对每个商品的价格历史数组按日期升序排序(确保时间顺序正确)
  {
    $addFields: {
      sortedHistory: { $sortArray: { input: "$priceHistory", sortBy: { date: 1 } } }
    }
  },
  // 第三步:提取需要的三个时间点价格
  {
    $project: {
      _id: 0,
      name: "$_id",
      price_last: { $last: "$sortedHistory.price" },
      price_1m_ago: {
        $let: {
          vars: {
            targetDate: { $subtract: [ { $last: "$sortedHistory.date" }, 60000 ] } // 最新时间减1分钟(60秒=60000毫秒)
          },
          in: {
            $getField: {
              field: "price",
              input: {
                $first: {
                  $filter: {
                    input: "$sortedHistory",
                    cond: { $gte: [ "$$this.date", "$$targetDate" ] }
                  }
                }
              }
            }
          }
        }
      },
      price_5m_ago: {
        $let: {
          vars: {
            targetDate: { $subtract: [ { $last: "$sortedHistory.date" }, 300000 ] } // 最新时间减5分钟(300秒=300000毫秒)
          },
          in: {
            $getField: {
              field: "price",
              input: {
                $first: {
                  $filter: {
                    input: "$sortedHistory",
                    cond: { $gte: [ "$$this.date", "$$targetDate" ] }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
])

关键步骤解释

  • $group阶段:把同一个商品的所有记录收集到priceHistory数组里,这样我们就能拿到每个商品的完整时间序列数据。
  • $addFields + $sortArray:确保价格历史是按时间升序排列的,这样$last就能准确拿到最新的记录,过滤的时候也能按顺序找到最接近目标时间的那条数据。
  • $project阶段:
    • price_last直接用$last取排序后数组的最后一个价格,就是最新价格。
    • price_1m_ago和price_5m_ago的逻辑一致:先计算目标时间(最新时间减去对应分钟数),然后用$filter找出所有晚于等于目标时间的记录,再用$first取最接近目标时间的那条,最后提取它的价格。

如果你的数据里每个时间点(比如整分钟)都有一条记录,这个查询会完美匹配你的需求;如果有缺失的时间点,它会取目标时间之后的第一条记录,也是合理的业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:17:50