diff options
author | James Wahlin <james@mongodb.com> | 2017-06-20 12:42:00 -0400 |
---|---|---|
committer | James Wahlin <james@mongodb.com> | 2017-06-22 12:04:47 -0400 |
commit | 04da0519f6b80bd75fb6920881b0ea211f6b277a (patch) | |
tree | 512ea2a4bc355b651986e2aa65a3cc88b4287ad2 /jstests | |
parent | 46f57a1e5213b0c06b54dcc65286f199155c126a (diff) | |
download | mongo-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.js | 112 | ||||
-rw-r--r-- | jstests/core/views/views_aggregation.js | 35 | ||||
-rw-r--r-- | jstests/noPassthrough/max_bson_depth_parameter.js | 25 |
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"}); |