英文:
Mongo $sort and then $group, is order guaranteed?
问题
我有一堆表示游戏中得分的文件。我想按用户ID对得分进行分组并求和,但有一个要注意的地方:得分可能是负数,但累积总数不应低于零。例如,如果用户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'],
},
],
},
},
},
},
}
]
这依赖于按正确顺序(按earnedDate
升序)将points
推送到pointDeltas
中。
根据我的实验,似乎确实会按正确顺序处理。但这是否被保证了呢?
我注意到$first
操作符的官方文档中有这样的说明:
如果文档已排序,则仅定义顺序。
这似乎是一个提示,表明文档是按顺序处理的,尽管不太清楚这个原则是否也适用于使用$push
。在同一页上$push
的文档没有类似的注释。
这种行为是被保证的还是巧合的?我还没有找到确凿的答案。
英文:
I have a bunch of documents representing points scored in a game. I want to group the points by user ID and sum them, with a gotcha: it's possible to score negative points, but the running sum should never go below zero. So for example if user 1 scored the following points in this order:
1
2
-5
3
Then their final score should be 3
, because the -5
only takes them down to 0 total, rather than -2
.
I have this aggregation pipeline which, as far as I can tell, correctly accomplishes this:
[
{
$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'],
},
],
},
},
},
},
}
]
This depends on the points
being pushed onto pointDeltas
in the right order (by earnedDate
, ascending).
Experimentally, this does seem to happen. But is this guaranteed?
I noticed the official documentation for the $first
operator states:
> Returns a value from the first document for each group. Order is only defined if the documents are sorted.
This seems like a hint that the documents are processed in order, though it's not 100% clear if this principle applies to using $push
too. The documentation for $push
on the same page does not have a similar note.
Is this behavior guaranteed or coincidental? I haven't been able to find any bulletproof answer either way.
答案1
得分: 1
根据$push中的示例,文档是有序的。
我建议在https://jira.mongodb.org/上提出一个案例。在那里提出您的问题和/或请求文档的扩展。
如果您想要绝对确定,那么您可以使用以下内容:
[
{
$group: {
_id: '$userId',
pointDeltas: {
$push: { points: "$points", earnedDate: "$earnedDate" }
},
userId: { $first: '$userId' },
},
},
{
$set: {
pointDeltas: {
input: "$pointDeltas",
sortBy: { earnedDate: 1 }
}
}
},
{
$project: {
userId: 1,
points: {
$reduce: {
input: '$pointDeltas',
initialValue: 0,
in: {
$max: [
0,
{ $add: ['$$value.points', '$$this.points'], }
]
}
}
}
}
}
]
英文:
According the examples in $push the documents are ordered.
I would suggest to open a case in https://jira.mongodb.org/. Ask your question there and/or request an extension in the documentation.
if you like to be absolutely sure, then you can use this one:
[
{
$group: {
_id: '$userId',
pointDeltas: {
$push: { points: "$points", earnedDate: "$earnedDate" }
},
userId: { $first: '$userId' },
},
},
{
$set: {
pointDeltas: {
input: "$pointDeltas",
sortBy: { earnedDate: 1 }
}
}
},
{
$project: {
userId: 1,
points: {
$reduce: {
input: '$pointDeltas',
initialValue: 0,
in: {
$max: [
0,
{ $add: ['$$value.points', '$$this.points'], }
]
}
}
}
}
}
]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论