diff options
author | samontea <merciers.merciers@gmail.com> | 2021-06-03 14:25:19 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-06-03 14:46:23 +0000 |
commit | 37767309fa36d7828e41618f0d940f9ac6fa4a65 (patch) | |
tree | 3731be028a1e86d96a3d4c95463bf32a649e19c5 | |
parent | c03426c28f007425e0aa7de65e3ca9509624128a (diff) | |
download | mongo-37767309fa36d7828e41618f0d940f9ac6fa4a65.tar.gz |
SERVER-56449 Allow $derivative and $integral to use descending sortBy (document windows)
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 { |