Skip to content

Commit e0ca1b4

Browse files
daprahamianmbroadst
authored andcommitted
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
1 parent 40f5872 commit e0ca1b4

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

lib/collection.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -2475,7 +2475,12 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
24752475
options = getReadPreference(this, options, this.s.db, this);
24762476

24772477
// If explain has been specified add it
2478-
if (options.explain) command.explain = options.explain;
2478+
if (options.explain) {
2479+
if (command.readConcern || command.writeConcern) {
2480+
throw toError('"explain" cannot be used on an aggregate call with readConcern/writeConcern');
2481+
}
2482+
command.explain = options.explain;
2483+
}
24792484

24802485
if (typeof options.comment === 'string') command.comment = options.comment;
24812486

test/functional/aggregation_tests.js

+52
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,58 @@ describe('Aggregation', function() {
942942
}
943943
});
944944

945+
it('should fail if you try to use explain flag with readConcern/writeConcern', {
946+
metadata: {
947+
requires: {
948+
mongodb: '>3.6.0',
949+
topology: 'single'
950+
}
951+
},
952+
953+
test: function(done) {
954+
var databaseName = this.configuration.db;
955+
var client = this.configuration.newClient(this.configuration.writeConcernMax(), {
956+
poolSize: 1
957+
});
958+
959+
const testCases = [
960+
{readConcern: {level: 'local'}},
961+
{writeConcern: {j: true},},
962+
{readConcern: {level: 'local'}, writeConcern: {j: true}},
963+
];
964+
965+
client.connect(function(err, client) {
966+
const wrapup = (err) => {
967+
client.close();
968+
done(err);
969+
};
970+
971+
const db = client.db(databaseName);
972+
973+
Promise.all(testCases.map((testCase) => {
974+
const stringifiedTestCase = JSON.stringify(testCase);
975+
const collection = db.collection('foo');
976+
Object.assign(collection.s, testCase);
977+
try {
978+
const promise = collection.aggregate([
979+
{$project: {_id: 0}},
980+
{$out: 'bar'}
981+
], {explain: true}).toArray().then(() => {
982+
throw new Error('Expected aggregation to not succeed for options ' + stringifiedTestCase)
983+
}, () => {
984+
throw new Error('Expected aggregation to fail on client instead of server for options ' + stringifiedTestCase)
985+
});
986+
987+
return promise;
988+
} catch (e) {
989+
expect(e).to.exist;
990+
return Promise.resolve();
991+
}
992+
})).then(() => wrapup(), wrapup);
993+
});
994+
}
995+
});
996+
945997
/**
946998
* Correctly call the aggregation framework to return a cursor with batchSize 1 and get the first result using next
947999
*

0 commit comments

Comments
 (0)