summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorJames Wahlin <james@mongodb.com>2017-06-20 12:42:00 -0400
committerJames Wahlin <james@mongodb.com>2017-06-22 12:04:47 -0400
commit04da0519f6b80bd75fb6920881b0ea211f6b277a (patch)
tree512ea2a4bc355b651986e2aa65a3cc88b4287ad2 /jstests
parent46f57a1e5213b0c06b54dcc65286f199155c126a (diff)
downloadmongo-04da0519f6b80bd75fb6920881b0ea211f6b277a.tar.gz
SERVER-29371 Add support for lite parse of namespace in nested $lookup
Diffstat (limited to 'jstests')
-rw-r--r--jstests/aggregation/sources/lookup/lookup.js112
-rw-r--r--jstests/core/views/views_aggregation.js35
-rw-r--r--jstests/noPassthrough/max_bson_depth_parameter.js25
3 files changed, 167 insertions, 5 deletions
diff --git a/jstests/aggregation/sources/lookup/lookup.js b/jstests/aggregation/sources/lookup/lookup.js
index 8d761814de3..c5314fb7f25 100644
--- a/jstests/aggregation/sources/lookup/lookup.js
+++ b/jstests/aggregation/sources/lookup/lookup.js
@@ -16,13 +16,23 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
return 0;
}
+ function generateNestedPipeline(foreignCollName, numLevels) {
+ let pipeline = [{"$lookup": {pipeline: [], from: foreignCollName, as: "same"}}];
+
+ for (let level = 0; level < numLevels; level++) {
+ pipeline = [{"$lookup": {pipeline: pipeline, from: foreignCollName, as: "same"}}];
+ }
+
+ return pipeline;
+ }
+
// Helper for testing that pipeline returns correct set of results.
function testPipeline(pipeline, expectedResult, collection) {
assert.eq(collection.aggregate(pipeline).toArray().sort(compareId),
expectedResult.sort(compareId));
}
- function runTest(coll, from) {
+ function runTest(coll, from, thirdColl, fourthColl) {
var db = null; // Using the db variable is banned in this function.
assert.writeOK(coll.insert({_id: 0, a: 1}));
@@ -598,6 +608,78 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
17276);
//
+ // Pipeline syntax with nested $lookup.
+ //
+ coll.drop();
+ assert.writeOK(coll.insert({_id: 1, w: 1}));
+ assert.writeOK(coll.insert({_id: 2, w: 2}));
+ assert.writeOK(coll.insert({_id: 3, w: 3}));
+
+ from.drop();
+ assert.writeOK(from.insert({_id: 1, x: 1}));
+ assert.writeOK(from.insert({_id: 2, x: 2}));
+ assert.writeOK(from.insert({_id: 3, x: 3}));
+
+ thirdColl.drop();
+ assert.writeOK(thirdColl.insert({_id: 1, y: 1}));
+ assert.writeOK(thirdColl.insert({_id: 2, y: 2}));
+ assert.writeOK(thirdColl.insert({_id: 3, y: 3}));
+
+ fourthColl.drop();
+ assert.writeOK(fourthColl.insert({_id: 1, z: 1}));
+ assert.writeOK(fourthColl.insert({_id: 2, z: 2}));
+ assert.writeOK(fourthColl.insert({_id: 3, z: 3}));
+
+ // Nested $lookup pipeline.
+ pipeline = [
+ {$match: {_id: 1}},
+ {
+ $lookup: {
+ pipeline: [
+ {$match: {_id: 2}},
+ {
+ $lookup: {
+ pipeline: [
+ {$match: {_id: 3}},
+ {
+ $lookup: {
+ pipeline: [
+ {$match: {_id: 1}},
+ ],
+ from: "fourthColl",
+ as: "thirdLookup"
+ }
+ },
+ ],
+ from: "thirdColl",
+ as: "secondLookup"
+ }
+ },
+ ],
+ from: "from",
+ as: "firstLookup",
+ }
+ }
+ ];
+
+ expectedResults = [{
+ "_id": 1,
+ "w": 1,
+ "firstLookup": [{
+ "_id": 2,
+ x: 2, "secondLookup": [{"_id": 3, y: 3, "thirdLookup": [{_id: 1, z: 1}]}]
+ }]
+ }];
+ testPipeline(pipeline, expectedResults, coll);
+
+ // Deeply nested $lookup pipeline. Each $lookup stage adds 3 levels to the JSON object
+ // depth. The chosen depth allows for an aggregate command that is within the JSON-to-BSON
+ // conversion depth limit of 150 (with a small buffer to allow for running this test in
+ // passthroughs that may wrap a given pipeline, increasing depth).
+ const nestedPipeline = generateNestedPipeline("lookup", 45);
+ coll.aggregate(nestedPipeline);
+
+ //
// Error cases.
//
@@ -657,9 +739,9 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
// 'pipeline' and 'let' must be of expected type.
assertErrorCode(
- coll, [{$lookup: {pipeline: 1, from: "from", as: "as"}}], ErrorCodes.FailedToParse);
+ coll, [{$lookup: {pipeline: 1, from: "from", as: "as"}}], ErrorCodes.TypeMismatch);
assertErrorCode(
- coll, [{$lookup: {pipeline: {}, from: "from", as: "as"}}], ErrorCodes.FailedToParse);
+ coll, [{$lookup: {pipeline: {}, from: "from", as: "as"}}], ErrorCodes.TypeMismatch);
assertErrorCode(coll,
[{$lookup: {let : 1, pipeline: [], from: "from", as: "as"}}],
ErrorCodes.FailedToParse);
@@ -678,20 +760,40 @@ load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
// Run tests on single node.
db.lookUp.drop();
db.from.drop();
- runTest(db.lookUp, db.from);
+ db.thirdColl.drop();
+ db.fourthColl.drop();
+ runTest(db.lookUp, db.from, db.thirdColl, db.fourthColl);
// Run tests in a sharded environment.
var sharded = new ShardingTest({shards: 2, mongos: 1});
assert(sharded.adminCommand({enableSharding: "test"}));
sharded.getDB('test').lookUp.drop();
sharded.getDB('test').from.drop();
+ sharded.getDB('test').thirdColl.drop();
+ sharded.getDB('test').fourthColl.drop();
assert(sharded.adminCommand({shardCollection: "test.lookUp", key: {_id: 'hashed'}}));
- runTest(sharded.getDB('test').lookUp, sharded.getDB('test').from);
+ runTest(sharded.getDB('test').lookUp,
+ sharded.getDB('test').from,
+ sharded.getDB('test').thirdColl,
+ sharded.getDB('test').fourthColl);
// An error is thrown if the from collection is sharded.
assert(sharded.adminCommand({shardCollection: "test.from", key: {_id: 1}}));
assertErrorCode(sharded.getDB('test').lookUp,
[{$lookup: {localField: "a", foreignField: "b", from: "from", as: "same"}}],
28769);
+
+ // An error is thrown if nested $lookup from collection is sharded.
+ assert(sharded.adminCommand({shardCollection: "test.fourthColl", key: {_id: 1}}));
+ assertErrorCode(sharded.getDB('test').lookUp,
+ [{
+ $lookup: {
+ pipeline: [{$lookup: {pipeline: [], from: "fourthColl", as: "same"}}],
+ from: "thirdColl",
+ as: "same"
+ }
+ }],
+ 28769);
+
sharded.stop();
}());
diff --git a/jstests/core/views/views_aggregation.js b/jstests/core/views/views_aggregation.js
index a0c5392deb4..2f2333ddf24 100644
--- a/jstests/core/views/views_aggregation.js
+++ b/jstests/core/views/views_aggregation.js
@@ -252,6 +252,41 @@
graphLookupPipeline,
[{_id: "New York", matchedId1: "New York", matchedId2: "New York"}]);
+ // Test that the $lookup stage on a view with a nested $lookup on a different view resolves the
+ // view namespaces referenced in their respective 'from' fields.
+ assertAggResultEq(
+ coll.getName(),
+ [
+ {$match: {_id: "Trenton"}},
+ {$project: {state: 1}},
+ {
+ $lookup: {
+ from: "identityView",
+ as: "lookup1",
+ pipeline: [
+ {$match: {_id: "Trenton"}},
+ {$project: {state: 1}},
+ {$lookup: {from: "popSortedView", as: "lookup2", pipeline: []}}
+ ]
+ }
+ }
+ ],
+ [{
+ "_id": "Trenton",
+ "state": "NJ",
+ "lookup1": [{
+ "_id": "Trenton",
+ "state": "NJ",
+ "lookup2": [
+ {"_id": "Newark", "state": "NJ", "pop": 3},
+ {"_id": "San Francisco", "state": "CA", "pop": 4},
+ {"_id": "Trenton", "state": "NJ", "pop": 5},
+ {"_id": "New York", "state": "NY", "pop": 7},
+ {"_id": "Palo Alto", "state": "CA", "pop": 10}
+ ]
+ }]
+ }]);
+
// Test that the $facet stage resolves the view namespace referenced in the 'from' field of a
// $lookup stage nested inside of a $graphLookup stage.
assertAggResultEq(
diff --git a/jstests/noPassthrough/max_bson_depth_parameter.js b/jstests/noPassthrough/max_bson_depth_parameter.js
index 337205d3134..ec71f659e6d 100644
--- a/jstests/noPassthrough/max_bson_depth_parameter.js
+++ b/jstests/noPassthrough/max_bson_depth_parameter.js
@@ -12,12 +12,37 @@
let conn = MongoRunner.runMongod({setParameter: "maxBSONDepth=5"});
assert.neq(null, conn, "Failed to start mongod");
let testDB = conn.getDB("test");
+
assert.commandWorked(testDB.runCommand({ping: 1}), "Failed to run a command on the server");
assert.commandFailedWithCode(
testDB.runCommand({find: "coll", filter: {x: {x: {x: {x: {x: {x: 1}}}}}}}),
ErrorCodes.Overflow,
"Expected server to reject command for exceeding the nesting depth limit");
+ // Confirm depth limits for $lookup.
+ assert.writeOK(testDB.coll1.insert({_id: 1}));
+ assert.writeOK(testDB.coll2.insert({_id: 1}));
+
+ assert.commandWorked(testDB.runCommand({
+ aggregate: "coll1",
+ pipeline: [{$lookup: {from: "coll2", as: "as", pipeline: []}}],
+ cursor: {}
+ }));
+ assert.commandFailedWithCode(
+ testDB.runCommand({
+ aggregate: "coll1",
+ pipeline: [{
+ $lookup: {
+ from: "coll2",
+ as: "as",
+ pipeline: [{$lookup: {from: "coll2", as: "as", pipeline: []}}]
+ }
+ }],
+ cursor: {}
+ }),
+ ErrorCodes.Overflow,
+ "Expected server to reject command for exceeding the nesting depth limit");
+
// Restart mongod with a negative maximum BSON depth and test that it fails to start.
MongoRunner.stopMongod(conn);
conn = MongoRunner.runMongod({setParameter: "maxBSONDepth=-4"});