-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implemented $topN and $bottomN accumulators.
- Loading branch information
Showing
7 changed files
with
374 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// https://www.mongodb.com/docs/manual/reference/operator/aggregation/bottomN/#mongodb-group-grp.-bottomN | ||
import { Aggregator } from "../../aggregator"; | ||
import { ComputeOptions, computeValue, Options } from "../../core"; | ||
import { AnyVal, RawObject } from "../../types"; | ||
import { $push } from "./push"; | ||
|
||
interface InputExpr { | ||
n: number; | ||
sortBy: Record<string, number>; | ||
output: AnyVal; | ||
} | ||
|
||
/** | ||
* Returns an aggregation of the bottom n elements within a group, according to the specified sort order. | ||
* If the group contains fewer than n elements, $bottomN returns all elements in the group. | ||
* | ||
* @param {Array} collection The input array | ||
* @param {Object} expr The right-hand side expression value of the operator | ||
* @param {Options} options The options to use for this operation | ||
* @returns {*} | ||
*/ | ||
export function $bottomN( | ||
collection: RawObject[], | ||
expr: InputExpr, | ||
options?: Options | ||
): AnyVal[] { | ||
const copts = ComputeOptions.init(options); | ||
const { n, sortBy } = computeValue( | ||
copts.local.groupId, | ||
expr, | ||
null, | ||
copts | ||
) as { n: number; sortBy: Record<string, number> }; | ||
|
||
const result = new Aggregator([{ $sort: sortBy }], copts.options).run( | ||
collection | ||
); | ||
|
||
const m = result.length; | ||
return $push(n >= m ? result : result.slice(m - n), expr.output, copts); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// https://www.mongodb.com/docs/manual/reference/operator/aggregation/topN/#mongodb-group-grp.-topN | ||
import { Aggregator } from "../../aggregator"; | ||
import { ComputeOptions, computeValue, Options } from "../../core"; | ||
import { AnyVal, RawObject } from "../../types"; | ||
import { $push } from "./push"; | ||
|
||
interface InputExpr { | ||
n: number; | ||
sortBy: Record<string, number>; | ||
output: AnyVal; | ||
} | ||
|
||
/** | ||
* Returns an aggregation of the top n elements within a group, according to the specified sort order. | ||
* If the group contains fewer than n elements, $topN returns all elements in the group. | ||
* | ||
* @param {Array} collection The input array | ||
* @param {Object} expr The right-hand side expression value of the operator | ||
* @param {Options} options The options to use for this operation | ||
* @returns {*} | ||
*/ | ||
export function $topN( | ||
collection: RawObject[], | ||
expr: InputExpr, | ||
options?: Options | ||
): AnyVal[] { | ||
const copts = ComputeOptions.init(options); | ||
const { n, sortBy } = computeValue( | ||
copts.local.groupId, | ||
expr, | ||
null, | ||
copts | ||
) as { n: number; sortBy: Record<string, number> }; | ||
|
||
const result = new Aggregator( | ||
[{ $sort: sortBy }, { $limit: n }], | ||
copts.options | ||
).run(collection); | ||
|
||
return $push(result, expr.output, copts); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import * as samples from "../../support"; | ||
|
||
const docs = [ | ||
{ playerId: "PlayerA", gameId: "G1", score: 31 }, | ||
{ playerId: "PlayerB", gameId: "G1", score: 33 }, | ||
{ playerId: "PlayerC", gameId: "G1", score: 99 }, | ||
{ playerId: "PlayerD", gameId: "G1", score: 1 }, | ||
{ playerId: "PlayerA", gameId: "G2", score: 10 }, | ||
{ playerId: "PlayerB", gameId: "G2", score: 14 }, | ||
{ playerId: "PlayerC", gameId: "G2", score: 66 }, | ||
{ playerId: "PlayerD", gameId: "G2", score: 80 }, | ||
]; | ||
|
||
samples.runTestPipeline("operators/accumulator/bottomN", [ | ||
{ | ||
message: "Null and Missing Values", | ||
input: [ | ||
{ playerId: "PlayerA", gameId: "G1", score: 1 }, | ||
{ playerId: "PlayerB", gameId: "G1", score: 2 }, | ||
{ playerId: "PlayerC", gameId: "G1", score: 3 }, | ||
{ playerId: "PlayerD", gameId: "G1" }, | ||
{ playerId: "PlayerE", gameId: "G1", score: null }, | ||
], | ||
pipeline: [ | ||
{ | ||
$group: { | ||
_id: "$gameId", | ||
playerId: { | ||
$bottomN: { | ||
output: ["$playerId", "$score"], | ||
sortBy: { score: -1 }, | ||
n: 3, | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
expected: [ | ||
{ | ||
_id: "G1", | ||
playerId: [ | ||
["PlayerA", 1], | ||
["PlayerD", undefined], | ||
["PlayerE", null], | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
message: "Data Type Sort Ordering", | ||
input: [ | ||
{ playerId: "PlayerA", gameId: "G1", score: 1 }, | ||
{ playerId: "PlayerB", gameId: "G1", score: "2" }, | ||
{ playerId: "PlayerC", gameId: "G1", score: "" }, | ||
], | ||
pipeline: [ | ||
{ | ||
$group: { | ||
_id: "$gameId", | ||
playerId: { | ||
$bottomN: { | ||
output: ["$playerId", "$score"], | ||
sortBy: { score: -1 }, | ||
n: 3, | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
expected: [ | ||
{ | ||
_id: "G1", | ||
playerId: [ | ||
["PlayerB", "2"], | ||
["PlayerC", ""], | ||
["PlayerA", 1], | ||
], | ||
}, | ||
], | ||
}, | ||
|
||
{ | ||
message: "Finding the Three Lowest Score Documents Across Multiple Games", | ||
input: docs, | ||
pipeline: [ | ||
{ | ||
$group: { | ||
_id: "$gameId", | ||
playerId: { | ||
$bottomN: { | ||
output: ["$playerId", "$score"], | ||
sortBy: { score: -1 }, | ||
n: 3, | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
expected: [ | ||
{ | ||
_id: "G1", | ||
playerId: [ | ||
["PlayerB", 33], | ||
["PlayerA", 31], | ||
["PlayerD", 1], | ||
], | ||
}, | ||
{ | ||
_id: "G2", | ||
playerId: [ | ||
["PlayerC", 66], | ||
["PlayerB", 14], | ||
["PlayerA", 10], | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
message: "Computing n Based on the Group Key for $group", | ||
input: docs, | ||
pipeline: [ | ||
{ | ||
$group: { | ||
_id: { gameId: "$gameId" }, | ||
gamescores: { | ||
$bottomN: { | ||
output: "$score", | ||
n: { | ||
$cond: { if: { $eq: ["$gameId", "G2"] }, then: 1, else: 3 }, | ||
}, | ||
sortBy: { score: -1 }, | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
expected: [ | ||
{ _id: { gameId: "G1" }, gamescores: [33, 31, 1] }, | ||
{ _id: { gameId: "G2" }, gamescores: [10] }, | ||
], | ||
}, | ||
]); |
Oops, something went wrong.