summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilitsa Sotirova <militsa.sotirova@mongodb.com>2022-09-14 18:00:53 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-14 20:26:03 +0000
commit7522eca50c6ce4792cd0ebc9a2a4bb65e3729642 (patch)
tree623b66f2b06eea1bef64c4a55ce81a30b0839cf7
parentdd9d37fa07a7af46ac4ee8dabeb235dc9571afb0 (diff)
downloadmongo-7522eca50c6ce4792cd0ebc9a2a4bb65e3729642.tar.gz
SERVER-68692 add support for limit and skip queries in ABT translation
-rw-r--r--jstests/cqf/find_limit_skip.js167
-rw-r--r--src/mongo/db/pipeline/abt/canonical_query_translation.cpp13
2 files changed, 178 insertions, 2 deletions
diff --git a/jstests/cqf/find_limit_skip.js b/jstests/cqf/find_limit_skip.js
new file mode 100644
index 00000000000..9f925b01ef8
--- /dev/null
+++ b/jstests/cqf/find_limit_skip.js
@@ -0,0 +1,167 @@
+(function() {
+"use strict";
+
+const coll = db.cqf_find_limit_skip;
+coll.drop();
+
+const docCount = 50;
+for (let i = 0; i < docCount; i++) {
+ assert.commandWorked(coll.insert({a: 2}));
+}
+
+const invalidValueErrorCode = 51024;
+
+// NEGATIVE LIMIT
+// The mongo shell implements the logic specified in the documentation for negative limits, so the
+// following command works as expected, i.e. the absolute value of the limit amount of documents is
+// returned (since that is less than the default batch size).
+let numReturned = coll.find().limit(-1).itcount();
+assert.eq(numReturned, 1);
+
+// This command will fail since a negative $limit field cannot be specified.
+assert.commandFailedWithCode(coll.runCommand({find: coll.getName(), filter: {}, limit: -1}),
+ invalidValueErrorCode);
+
+// Specify the batch size to ensure only one batch is returned with a negative limit. The default
+// batch size is greater than the limit.
+numReturned = coll.find().batchSize(3).limit(-10).itcount();
+assert.eq(numReturned, 3);
+
+// ZERO LIMIT
+numReturned = coll.find().limit(0).itcount();
+assert.eq(numReturned, docCount);
+
+// Showing that the command that failed with a negative $limit passes when the limit is >= 0.
+numReturned =
+ coll.runCommand({find: coll.getName(), filter: {}, limit: 0})["cursor"]["firstBatch"].length;
+assert.eq(numReturned, docCount);
+
+// POSITIVE LIMIT
+numReturned = coll.find().limit(10).itcount();
+assert.eq(numReturned, 10);
+
+// Specify the batch size to ensure that the amount of documents returned is the limit for a
+// positive limit.
+numReturned = coll.find().batchSize(3).limit(10).itcount();
+assert.eq(numReturned, 10);
+
+// NEGATIVE SKIP
+assert.commandFailedWithCode(coll.runCommand({find: coll.getName(), filter: {}, skip: -1}),
+ invalidValueErrorCode);
+
+// ZERO SKIP
+numReturned = coll.find().skip(0).itcount();
+assert.eq(numReturned, docCount);
+
+// POSITIVE SKIP
+numReturned = coll.find().skip(10).itcount();
+assert.eq(numReturned, docCount - 10);
+
+// Skip amount > docCount, should return 0 documents.
+numReturned = coll.find().skip(60).itcount();
+assert.eq(numReturned, 0);
+
+// NEGATIVE LIMIT, ZERO SKIP
+numReturned = coll.find().limit(-1).skip(0).itcount();
+assert.eq(numReturned, 1);
+
+// Specify the batch size to ensure only one batch is returned with a negative limit, zero skip.
+numReturned = coll.find().batchSize(3).limit(-10).skip(0).itcount();
+assert.eq(numReturned, 3);
+
+// NEGATIVE LIMIT, POSITIVE SKIP
+// Absolute value of limit amount > skip amount and docCount - skip amount > limit amount, should
+// return the absolute value of the limit amount of documents. (Note: default batch size > absolute
+// value of limit amount and default batch size > skip amount)
+let limitAmount = -10;
+let skipAmount = 1;
+numReturned = coll.find().limit(limitAmount).skip(skipAmount).itcount();
+assert.eq(numReturned, Math.abs(limitAmount));
+
+// Absolute value of limit amount > skip amount and docCount - skip amount < limit amount, should
+// return (docCount - skip amount) documents.
+limitAmount = -45;
+skipAmount = 40;
+numReturned = coll.find().limit(limitAmount).skip(skipAmount).itcount();
+assert.eq(numReturned, docCount - skipAmount);
+
+// Absolute value of limit amount > skip amount > batch size, should return one batch of documents.
+numReturned = coll.find().batchSize(3).limit(-10).skip(5).itcount();
+assert.eq(numReturned, 3);
+
+// Absolute value of limit amount > batch size > skip amount and batch size < docCount - skip
+// amount, should return one batch of documents.
+numReturned = coll.find().batchSize(5).limit(-10).skip(3).itcount();
+assert.eq(numReturned, 5);
+
+// Batch size > docCount - skip amount, should return the absolute value of the limit number of
+// documents.
+limitAmount = -10;
+skipAmount = 3;
+let batchSize = 45;
+numReturned = coll.find().batchSize(batchSize).limit(limitAmount).skip(skipAmount).itcount();
+assert.eq(numReturned, Math.abs(limitAmount));
+
+// Skip amount > batch size and docCount - limit amount > docCount - skip amount, should return
+// (docCount - skip amount) documents.
+limitAmount = -10;
+skipAmount = 47;
+batchSize = 45;
+numReturned = coll.find().batchSize(batchSize).limit(limitAmount).skip(skipAmount).itcount();
+assert.eq(numReturned, docCount - skipAmount);
+
+// Absolute value of limit amount < skip amount, should return the absolute value of the limit
+// amount of documents.
+numReturned = coll.find().limit(-1).skip(10).itcount();
+assert.eq(numReturned, 1);
+
+// Batch size < absolute value of limit amount < skip amount < docCount, should return one batch of
+// documents.
+numReturned = coll.find().batchSize(3).limit(-5).skip(10).itcount();
+assert.eq(numReturned, 3);
+
+// Absolute value of limit amount = skip amount < docCount, should return the absolute value of the
+// limit amount of documents.
+numReturned = coll.find().limit(-10).skip(10).itcount();
+assert.eq(numReturned, 10);
+
+// Absolute value of limit amount = skip amount = batchsize < docCount, should return one batch of
+// documents.
+numReturned = coll.find().batchSize(10).limit(-10).skip(10).itcount();
+assert.eq(numReturned, 10);
+
+// Absolute value of limit amount = skip amount = batchsize > docCount, should return 0 documents.
+numReturned = coll.find().batchSize(60).limit(-60).skip(60).itcount();
+assert.eq(numReturned, 0);
+
+// ZERO LIMIT, ZERO SKIP
+numReturned = coll.find().limit(0).skip(0).itcount();
+assert.eq(numReturned, docCount);
+
+// POSITIVE LIMIT, ZERO SKIP
+numReturned = coll.find().limit(10).skip(0).itcount();
+assert.eq(numReturned, 10);
+
+// ZERO LIMIT, POSITIVE SKIP
+numReturned = coll.find().limit(0).skip(10).itcount();
+assert.eq(numReturned, docCount - 10);
+
+// POSITIVE LIMIT, POSITIVE SKIP
+// Limit amount > skip amount, should return (limit) documents.
+numReturned = coll.find().limit(10).skip(1).itcount();
+assert.eq(numReturned, 10);
+
+// Limit amount < skip amount, should return (limit) documents.
+numReturned = coll.find().limit(1).skip(10).itcount();
+assert.eq(numReturned, 1);
+
+// Limit amount = skip amount, should return (limit) documents.
+numReturned = coll.find().limit(10).skip(10).itcount();
+assert.eq(numReturned, 10);
+
+// (docCount - skip amount) < limit, should return (docCount - skip amount) documents.
+limitAmount = 40;
+skipAmount = 15;
+numReturned = coll.find().limit(limitAmount).skip(skipAmount).itcount();
+assert.eq(numReturned, docCount - skipAmount);
+}());
diff --git a/src/mongo/db/pipeline/abt/canonical_query_translation.cpp b/src/mongo/db/pipeline/abt/canonical_query_translation.cpp
index 066f060d81f..87c13355f37 100644
--- a/src/mongo/db/pipeline/abt/canonical_query_translation.cpp
+++ b/src/mongo/db/pipeline/abt/canonical_query_translation.cpp
@@ -59,8 +59,17 @@ ABT translateCanonicalQueryToABT(const Metadata& metadata,
translateProjection(ctx, scanProjName, canonicalQuery.getExpCtx(), proj);
}
- // TODO SERVER-68692: Support limit.
- // TODO SERVER-68693: Support skip.
+ auto skipAmount = canonicalQuery.getFindCommandRequest().getSkip();
+ auto limitAmount = canonicalQuery.getFindCommandRequest().getLimit();
+
+ if (limitAmount || skipAmount) {
+ ctx.setNode<LimitSkipNode>(
+ std::move(ctx.getNode()._rootProjection),
+ properties::LimitSkipRequirement(
+ limitAmount.value_or(properties::LimitSkipRequirement::kMaxVal),
+ skipAmount.value_or(0)),
+ std::move(ctx.getNode()._node));
+ }
return make<RootNode>(properties::ProjectionRequirement{ProjectionNameVector{
std::move(ctx.getNode()._rootProjection)}},