MongoDB如何使用aggregate()计算活动期间已消耗的已采购糖果总量
实现思路
这个需求属于时序先进先出(FIFO)的库存扣减统计,核心逻辑是按时间先后顺序,优先消耗活动期间采购的糖果,统计所有消耗掉的活动采购糖果总量。
MongoDB可以通过聚合管道结合自定义累加器实现,步骤如下:
步骤1:时序排序
首先用$sort按hour字段升序排序,保证按时间从早到晚处理数据:
{ $sort: { hour: 1 } }
步骤2:自定义累加器计算目标值
用$group配合$accumulator自定义状态累加逻辑,维护两个状态变量:
remaining_party_stock:活动期间采购、还未被消耗的糖果库存total:已经消耗的活动采购糖果总量,也就是我们要的结果
每一条数据的处理逻辑:
- 先把当期采购的
candies_bought加到remaining_party_stock - 当期需要消耗的
candies_eaten,优先从remaining_party_stock扣减:- 如果
remaining_party_stock >= candies_eaten:直接扣减对应库存,total加candies_eaten - 如果
remaining_party_stock < candies_eaten:把remaining_party_stock全部加到total,库存清0,剩下的消耗默认从非活动初始库存扣减,不影响统计结果
- 如果
完整的$group阶段代码:
{ $group: { _id: null, total_consumed_candies_that_were_bought_during_party: { $accumulator: { init: function() { return { remaining: 0, total: 0 } }, accumulate: function(state, bought, eaten) { // 先累加当期采购量 state.remaining += bought // 计算从活动库存扣减的消耗量 const consume_from_party = Math.min(state.remaining, eaten) state.total += consume_from_party state.remaining -= consume_from_party return state }, accumulateArgs: ["$candies_bought", "$candies_eaten"], merge: function(state1, state2) { // 全量排序后不会触发merge逻辑,此处做兼容即可 return { remaining: state1.remaining + state2.remaining, total: state1.total + state2.total } }, finalize: function(state) { return state.total } } } } }
步骤3:可选格式化输出
如果需要去掉返回结果里的_id字段,再加一个$project阶段即可:
{ $project: { _id: 0 } }
结果验证
针对你提供的样例数据,运行上述聚合管道后,会准确得到输出:
{"total_consumed_candies_that_were_bought_during_party": 11}
和预期结果完全一致。
内容的提问来源于stack exchange,提问作者Fusion
相关产品推荐
相关产品推荐

