summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsamontea <merciers.merciers@gmail.com>2021-06-03 14:25:19 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-03 14:46:23 +0000
commit37767309fa36d7828e41618f0d940f9ac6fa4a65 (patch)
tree3731be028a1e86d96a3d4c95463bf32a649e19c5
parentc03426c28f007425e0aa7de65e3ca9509624128a (diff)
downloadmongo-37767309fa36d7828e41618f0d940f9ac6fa4a65.tar.gz
SERVER-56449 Allow $derivative and $integral to use descending sortBy (document windows)
-rw-r--r--jstests/aggregation/sources/setWindowFields/derivative.js17
-rw-r--r--jstests/aggregation/sources/setWindowFields/integral.js20
-rw-r--r--src/mongo/db/pipeline/window_function/window_function_exec.cpp10
-rw-r--r--src/mongo/db/pipeline/window_function/window_function_expression.h3
4 files changed, 41 insertions, 9 deletions
diff --git a/jstests/aggregation/sources/setWindowFields/derivative.js b/jstests/aggregation/sources/setWindowFields/derivative.js
index 173f7e5e493..f125bf96872 100644
--- a/jstests/aggregation/sources/setWindowFields/derivative.js
+++ b/jstests/aggregation/sources/setWindowFields/derivative.js
@@ -117,6 +117,23 @@ assert.docEq(result, [
// time: 4 and time: 7.
{time: 7, y: 118, dy: +3 / 3},
]);
+// Because the derivative is the same irrespective of sort order (as long as we reexpress the
+// bounds) we can compare this result with the result of the previous aggregation.
+const resultDesc =
+ coll.aggregate([
+ {
+ $setWindowFields: {
+ sortBy: {time: -1},
+ output: {
+ dy: {$derivative: {input: "$y"}, window: {documents: [-1, +3]}},
+ }
+ }
+ },
+ {$unset: "_id"},
+ {$sort: {time: 1}},
+ ])
+ .toArray();
+assert.docEq(result, resultDesc);
// Example with range-based bounds.
coll.drop();
diff --git a/jstests/aggregation/sources/setWindowFields/integral.js b/jstests/aggregation/sources/setWindowFields/integral.js
index 097ea70536a..196c3d463a8 100644
--- a/jstests/aggregation/sources/setWindowFields/integral.js
+++ b/jstests/aggregation/sources/setWindowFields/integral.js
@@ -70,6 +70,26 @@ assert.sameMembers(result, [
{partitionID: 2, x: 4, y: 107, integral: 212}, // (105 + 107) * 2 / 2 = 212
{partitionID: 2, x: 6, y: -100, integral: 7}, // (107 - 100) * 2 / 2 = 7
]);
+// Because the integral from a to b is the same as the inverse of the integral from b to a, we can
+// invert the input, sort order, and bounds so that the results are the same as the previous
+// integral.
+const resultDesc = coll.aggregate([
+ {
+ $setWindowFields: {
+ partitionBy: "$partitionID",
+ sortBy: {x: -1},
+ output: {
+ integral: {
+ $integral: {input: {$subtract: [0, "$y"]}},
+ window: {documents: [0, +1]}
+ },
+ }
+ }
+ },
+ {$unset: "_id"},
+ ])
+ .toArray();
+assert.sameMembers(result, resultDesc);
// 'outputUnit' only supports 'week' and smaller.
coll.drop();
diff --git a/src/mongo/db/pipeline/window_function/window_function_exec.cpp b/src/mongo/db/pipeline/window_function/window_function_exec.cpp
index 00ca373d6a3..4619ef46bdd 100644
--- a/src/mongo/db/pipeline/window_function/window_function_exec.cpp
+++ b/src/mongo/db/pipeline/window_function/window_function_exec.cpp
@@ -56,9 +56,8 @@ boost::intrusive_ptr<Expression> translateInputExpression(
if (auto integral = dynamic_cast<window_function::ExpressionIntegral*>(expr.get())) {
auto expCtx = integral->expCtx();
tassert(5558802,
- "$integral requires a 1-field ascending sortBy",
- sortBy && sortBy->size() == 1 && !sortBy->begin()->expression &&
- sortBy->begin()->isAscending);
+ "$integral requires a 1-field sortBy",
+ sortBy && sortBy->size() == 1 && !sortBy->begin()->expression);
auto sortByExpr = ExpressionFieldPath::createPathFromString(
expCtx, sortBy->begin()->fieldPath->fullPath(), expCtx->variablesParseState);
return ExpressionArray::create(
@@ -97,9 +96,8 @@ std::unique_ptr<mongo::WindowFunctionExec> translateDerivative(
const boost::optional<SortPattern>& sortBy,
MemoryUsageTracker::PerFunctionMemoryTracker* memTracker) {
tassert(5490703,
- "$derivative requires a 1-field ascending sortBy",
- sortBy && sortBy->size() == 1 && !sortBy->begin()->expression &&
- sortBy->begin()->isAscending);
+ "$derivative requires a 1-field sortBy",
+ sortBy && sortBy->size() == 1 && !sortBy->begin()->expression);
auto sortExpr =
ExpressionFieldPath::createPathFromString(expr->expCtx(),
sortBy->begin()->fieldPath->fullPath(),
diff --git a/src/mongo/db/pipeline/window_function/window_function_expression.h b/src/mongo/db/pipeline/window_function/window_function_expression.h
index 526c519ede4..52fe79e5b48 100644
--- a/src/mongo/db/pipeline/window_function/window_function_expression.h
+++ b/src/mongo/db/pipeline/window_function/window_function_expression.h
@@ -484,9 +484,6 @@ protected:
uassert(ErrorCodes::FailedToParse,
str::stream() << accumulatorName << " requires a non-expression sortBy",
!sortBy->begin()->expression);
- uassert(ErrorCodes::FailedToParse,
- str::stream() << accumulatorName << " requires an ascending sortBy",
- sortBy->begin()->isAscending);
}
boost::optional<long long> convertTimeUnitToMillis(boost::optional<TimeUnit> outputUnit) const {