summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2017-06-21 15:07:52 -0400
committerDavid Storch <david.storch@10gen.com>2017-06-26 15:57:27 -0400
commit8bc18f2367d616ef1e68b3be4acfaa1d2e8daa6e (patch)
tree90b1a2bf186a9901fca1b4c901a0ce6212793cc9
parentde969ba464dfe0e3d5ffd45dd4f5b6cec824e775 (diff)
downloadmongo-8bc18f2367d616ef1e68b3be4acfaa1d2e8daa6e.tar.gz
SERVER-29647 Fix $match swapping to avoid moving before $sort-$limit.
(cherry picked from commit 8b8845703f0c92bafca58ce5d9f36fd2327301d1) Conflicts: jstests/core/views/views_aggregation.js
-rw-r--r--jstests/aggregation/bugs/match_swap_limit.js20
-rw-r--r--src/mongo/db/pipeline/document_source_sort.h4
-rw-r--r--src/mongo/db/pipeline/pipeline_test.cpp23
3 files changed, 46 insertions, 1 deletions
diff --git a/jstests/aggregation/bugs/match_swap_limit.js b/jstests/aggregation/bugs/match_swap_limit.js
new file mode 100644
index 00000000000..3de26d6f4b5
--- /dev/null
+++ b/jstests/aggregation/bugs/match_swap_limit.js
@@ -0,0 +1,20 @@
+/**
+ * Ensure that $match is always applied after $limit.
+ */
+(function() {
+ "use strict";
+
+ let coll = db.jstests_match_swap_limit;
+ coll.drop();
+
+ assert.writeOK(coll.insert({_id: 0, x: 1, y: 3}));
+ assert.writeOK(coll.insert({_id: 1, x: 2, y: 2}));
+ assert.writeOK(coll.insert({_id: 2, x: 3, y: 1}));
+
+ assert.eq([{_id: 1, x: 2, y: 2}],
+ coll.aggregate([{$sort: {x: -1}}, {$limit: 2}, {$match: {y: {$gte: 2}}}]).toArray());
+
+ assert.writeOK(coll.createIndex({x: 1}));
+ assert.eq([{_id: 1, x: 2, y: 2}],
+ coll.aggregate([{$sort: {x: -1}}, {$limit: 2}, {$match: {y: {$gte: 2}}}]).toArray());
+}());
diff --git a/src/mongo/db/pipeline/document_source_sort.h b/src/mongo/db/pipeline/document_source_sort.h
index d9266011a55..0e4a427e77f 100644
--- a/src/mongo/db/pipeline/document_source_sort.h
+++ b/src/mongo/db/pipeline/document_source_sort.h
@@ -51,7 +51,9 @@ public:
}
bool canSwapWithMatch() const final {
- return true;
+ // Can't swap with a $match if a limit has been absorbed, since in general match can't swap
+ // with limit.
+ return !limitSrc;
}
BSONObjSet getOutputSorts() final {
diff --git a/src/mongo/db/pipeline/pipeline_test.cpp b/src/mongo/db/pipeline/pipeline_test.cpp
index 0df5816a905..ed4ea7aefee 100644
--- a/src/mongo/db/pipeline/pipeline_test.cpp
+++ b/src/mongo/db/pipeline/pipeline_test.cpp
@@ -870,6 +870,27 @@ class MatchShouldNotSwapBeforeSkip : public Base {
}
};
+class MatchCannotSwapWithLimit : public Base {
+ string inputPipeJson() final {
+ return "[{$limit: 3}, {$match: {x: {$gt: 0}}}]";
+ }
+ string outputPipeJson() final {
+ return inputPipeJson();
+ }
+};
+
+class MatchCannotSwapWithSortLimit : public Base {
+ string inputPipeJson() final {
+ return "[{$sort: {x: -1}}, {$limit: 3}, {$match: {x: {$gt: 0}}}]";
+ }
+ string outputPipeJson() final {
+ return "[{$sort: {sortKey: {x: -1}, limit: 3}}, {$match: {x: {$gt: 0}}}]";
+ }
+ string serializedPipeJson() override {
+ return inputPipeJson();
+ }
+};
+
} // namespace Local
namespace Sharded {
@@ -1492,6 +1513,8 @@ public:
add<Optimizations::Local::NeighboringMatchesShouldCoalesce>();
add<Optimizations::Local::MatchShouldNotSwapBeforeLimit>();
add<Optimizations::Local::MatchShouldNotSwapBeforeSkip>();
+ add<Optimizations::Local::MatchCannotSwapWithLimit>();
+ add<Optimizations::Local::MatchCannotSwapWithSortLimit>();
add<Optimizations::Sharded::Empty>();
add<Optimizations::Sharded::coalesceLookUpAndUnwind::ShouldCoalesceUnwindOnAs>();
add<Optimizations::Sharded::coalesceLookUpAndUnwind::