-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Query Optimization
-
None
-
None
-
None
-
None
-
None
-
None
-
None
The $bottomN, $topN, $maxN, and $minN accumulators all accept an n expression which permits the number of values for the group to be computed dynamically based on the group key. Here's a simple example with $maxN which set n to the value of the group key itself:
db.c.drop(); assert.commandWorked( db.c.insert([ {key: 1, val: 1}, {key: 1, val: 2}, {key: 1, val: 3}, {key: 2, val: 1}, {key: 2, val: 2}, {key: 2, val: 3}, ]), ); let groupStage = { $group: { _id: {key: "$key"}, res: {$maxN: {input: "$val", n: "$key"}}, }, }; let results = db.c.aggregate([groupStage]).toArray(); printjson(results);
This script prints the following:
[
{
"_id" : {
"key" : 1
},
"res" : [
3
]
},
{
"_id" : {
"key" : 2
},
"res" : [
3,
2
]
}
]
The problem is that this only works when the group key is an object. If the query is written so that it groups on {_id: "$key"} instead of {_id:{key:"$key}}, then there is no way for the n expression to refer to the value of the key.
The reason for this is here: https://github.com/mongodb/mongo/blob/e575bad0a556968d4c5d7cfd04438e252172a8be/src/mongo/db/pipeline/group_processor_base.cpp#L181-L182. If the group id is not a document, then the idDoc variable is set to the empty document. Then n expression then gets evaluated over this empty document, which means there is no way to refer to the value of the group key.
This is arguably not an implementation bug, but a flaw in the language design. It can be worked around by making the group key a single-field document rather than a scalar.