From e0ca1b4cf7389de593f70f1405ac18022a6c760a Mon Sep 17 00:00:00 2001 From: Dan Aprahamian Date: Mon, 4 Dec 2017 16:34:24 -0500 Subject: [PATCH] feat(aggregation): fail aggregation on explain + readConcern/writeConcern Aggregation should fail if you try to use the explain flag while you have a readConcern and/or writeConcern. BREAKING CHANGE: If you use aggregation, and try to use the explain flag while you have a readConcern or writeConcern, your query will fail --- lib/collection.js | 7 +++- test/functional/aggregation_tests.js | 52 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/collection.js b/lib/collection.js index d4f13e2757..bbe9bfc40b 100644 --- a/lib/collection.js +++ b/lib/collection.js @@ -2475,7 +2475,12 @@ Collection.prototype.aggregate = function(pipeline, options, callback) { options = getReadPreference(this, options, this.s.db, this); // If explain has been specified add it - if (options.explain) command.explain = options.explain; + if (options.explain) { + if (command.readConcern || command.writeConcern) { + throw toError('"explain" cannot be used on an aggregate call with readConcern/writeConcern'); + } + command.explain = options.explain; + } if (typeof options.comment === 'string') command.comment = options.comment; diff --git a/test/functional/aggregation_tests.js b/test/functional/aggregation_tests.js index 60ed07a203..68791b9c74 100644 --- a/test/functional/aggregation_tests.js +++ b/test/functional/aggregation_tests.js @@ -942,6 +942,58 @@ describe('Aggregation', function() { } }); + it('should fail if you try to use explain flag with readConcern/writeConcern', { + metadata: { + requires: { + mongodb: '>3.6.0', + topology: 'single' + } + }, + + test: function(done) { + var databaseName = this.configuration.db; + var client = this.configuration.newClient(this.configuration.writeConcernMax(), { + poolSize: 1 + }); + + const testCases = [ + {readConcern: {level: 'local'}}, + {writeConcern: {j: true},}, + {readConcern: {level: 'local'}, writeConcern: {j: true}}, + ]; + + client.connect(function(err, client) { + const wrapup = (err) => { + client.close(); + done(err); + }; + + const db = client.db(databaseName); + + Promise.all(testCases.map((testCase) => { + const stringifiedTestCase = JSON.stringify(testCase); + const collection = db.collection('foo'); + Object.assign(collection.s, testCase); + try { + const promise = collection.aggregate([ + {$project: {_id: 0}}, + {$out: 'bar'} + ], {explain: true}).toArray().then(() => { + throw new Error('Expected aggregation to not succeed for options ' + stringifiedTestCase) + }, () => { + throw new Error('Expected aggregation to fail on client instead of server for options ' + stringifiedTestCase) + }); + + return promise; + } catch (e) { + expect(e).to.exist; + return Promise.resolve(); + } + })).then(() => wrapup(), wrapup); + }); + } + }); + /** * Correctly call the aggregation framework to return a cursor with batchSize 1 and get the first result using next *