MongoDB先$sort再$group,$push的顺序是否有官方保障?
关于MongoDB聚合中$push排序顺序的疑问
需求与实现
我有一批代表游戏得分的文档,希望按用户ID分组计算积分总和,但有特殊规则:得分可为负,但累计积分不能低于0。例如用户1的得分顺序为1、2、-5、3,最终得分应为3,因为-5只会将积分降至0而非-2。
我编写了如下聚合管道,经测试可实现该需求:
[ { $sort: { earnedDate: 1, }, }, { $group: { _id: '$userId', pointDeltas: { $push: '$points', }, userId: { $first: '$userId', }, }, }, { $project: { userId: 1, points: { $reduce: { input: '$pointDeltas', initialValue: 0, in: { $max: [ 0, { $add: ['$$value', '$$this'], }, ], }, }, }, }, } ]
核心疑问
该管道依赖$push按earnedDate升序将points存入pointDeltas,实验中顺序符合预期,但不确定此行为是否有官方保障。我注意到$first操作符的官方文档指出:“返回每组第一个文档的值,仅当文档已排序时顺序才确定”,这似乎暗示文档按顺序处理,但不确定该原则是否适用于$push,且$push的文档无类似说明。请问此行为是有保障的还是偶然现象?
解答
这个行为是有官方保障的。
MongoDB聚合管道是按阶段依次执行的,每个阶段的输出会作为下一个阶段的输入。当你先通过$sort阶段对全局文档按earnedDate升序排序后,后续$group阶段处理每组内的文档时,会严格遵循这个排序后的顺序。虽然$push的官方文档没有像$first那样单独强调顺序,但$group阶段会保留$sort传入的文档顺序,因此$push会按该顺序将points元素存入数组。
你的管道逻辑是完全正确的,$reduce部分也准确实现了“累计积分不低于0”的规则,可以放心使用。
内容的提问来源于stack exchange,提问作者Aurast
相关产品推荐
相关产品推荐

