I have a data like:
[
{ "grp": "A", "seq": 1, "score": 1, x: 0 },
{ "grp": "A", "seq": 1, "score": 2, x: 0 },
{ "grp": "A", "seq": 1, "score": 3, x: 0 },
{ "grp": "A", "seq": 1, "score": 4, x: 0 }
]
Using $setWindowFields
,
{
partitionBy: "$grp",
sortBy: { seq: 1 },
output: {
x: {
$sum: "$score",
window: {
documents: ["unbounded", "current"]
}
},
}
}
I get:
[
{ "grp": "A", "seq": 1, "score": 1, x: 1 },
{ "grp": "A", "seq": 1, "score": 2, x: 3 },
{ "grp": "A", "seq": 1, "score": 3, x: 6 },
{ "grp": "A", "seq": 1, "score": 4, x: 10 }
]
I only need to retain the running sum (x
) for the last item of the partition.
[
{ "grp": "A", "seq": 1, "score": 1, x: 0 },
{ "grp": "A", "seq": 1, "score": 2, x: 0 },
{ "grp": "A", "seq": 1, "score": 3, x: 0 },
{ "grp": "A", "seq": 1, "score": 4, x: 10 }
]
I’ve been testing with $project
and $last
but I wasn’t able to make it work.
What is a better expression or additional stage do I need to use?
Thank you!
2
Answers
Not sure if there is a deterministic sorting in your dataset, but with the same sorting that you are using, you can assign
ordering
with$documentNumber
in your$setWindowFields
. Then, compute$rank
with theordering
field. The last document will haverank: 1
. You can use this with$cond
to conditionally set fieldx
Mongo Playground
Ray’s answer and cmgchess’s example are both a better approach than
group
, shown here. But worth having since you only need the sum on the last item in the group and not exactly a running sum.$setWindowFields
is better for an actual running sum, as per the pipeline in your question.Here, I’m sorting and grouping, then pushing all the docs to the list (so 100MB limit issue may occur), and setting
xs
the sum ofscore
.In order to update only the last
x
to this value, I slice the docs array and setx = xs
only on that one, and then unwind.Mongo Playground