如何在MongoDB中计算过去7天嵌套文档的最低价格并新增字段
解决方案
原始文档
{ "product_id": "10001", "product_name": "Banana", "product_date": "2022-10-20T00:00:00.000+00:00", "product_price": 255.15, "dates": { "2022-10-10": { "recorded_price": 195.15 }, "2022-10-15": { "recorded_price": 230.20 }, "2022-10-20": { "recorded_price": 255.20 } } }
需求目标
新增min_7day_price字段,取值为product_date过去7天内dates对象中的最低recorded_price。
可行聚合管道实现
通过多阶段聚合管道完成对象转数组、日期过滤、最小值计算:
db.collection.aggregate([ { $addFields: { // 将dates对象转为数组,每个元素包含日期(k)和价格对象(v) datesArray: { $objectToArray: "$dates" }, // 计算product_date往前推7天的时间点 sevenDaysAgo: { $subtract: ["$product_date", 7 * 24 * 60 * 60 * 1000] } } }, { $addFields: { // 过滤出过去7天内的价格记录 filteredDates: { $filter: { input: "$datesArray", cond: { $gte: [ { $toDate: "$$this.k" }, "$sevenDaysAgo" ] } } } } }, { $addFields: { // 提取过滤后的价格并取最小值 min_7day_price: { $min: "$filteredDates.v.recorded_price" } } }, { // 移除临时字段,保持文档整洁(可选) $project: { datesArray: 0, sevenDaysAgo: 0, filteredDates: 0 } } ])
阶段说明
第一阶段$addFields:
datesArray:用$objectToArray把嵌套的dates对象转换为可遍历的数组结构;sevenDaysAgo:通过毫秒数计算,得到product_date前7天的时间戳,作为日期过滤的阈值。
第二阶段$addFields:
- 用
$filter遍历数组,将日期字符串转为Date类型后,筛选出大于等于sevenDaysAgo的记录,只保留过去7天内的价格数据。
- 用
第三阶段$addFields:
- 用
$min聚合操作,从过滤后的价格列表中提取最小值,赋值给min_7day_price。
- 用
第四阶段$project:
- 可选步骤,移除过程中生成的临时字段,让最终文档结构和需求一致。
批量更新文档(可选)
如果需要直接更新集合中的所有符合条件的文档,而非仅查询结果,可使用updateMany配合聚合管道:
db.collection.updateMany( {}, // 此处可添加查询条件,限定要更新的文档范围 [ { $addFields: { datesArray: { $objectToArray: "$dates" }, sevenDaysAgo: { $subtract: ["$product_date", 7 * 24 * 60 * 60 * 1000] } } }, { $addFields: { filteredDates: { $filter: { input: "$datesArray", cond: { $gte: [{ $toDate: "$$this.k" }, "$sevenDaysAgo"] } } } } }, { $addFields: { min_7day_price: { $min: "$filteredDates.v.recorded_price" } } }, { $project: { datesArray: 0, sevenDaysAgo: 0, filteredDates: 0 } } ] )
内容的提问来源于stack exchange,提问作者bachi312
相关产品推荐
相关产品推荐

