Skip to content

Commit 21cdcf0

Browse files
committed
feat(Aggregate): support ReadConcern in aggregates with $out
Adds support for adding a ReadConcern to aggregates that have a $out stage when run against 4.2 servers. Some ReadConcerns (like linearizable) are still not supported by the server, but will still be added on to the outbound request. Fixes NODE-1880
1 parent 46b526e commit 21cdcf0

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

lib/operations/aggregate.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const toError = require('../utils').toError;
1111

1212
const DB_AGGREGATE_COLLECTION = 1;
1313

14+
const MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT = 8;
15+
1416
/**
1517
* Perform an aggregate operation. See Collection.prototype.aggregate or Db.prototype.aggregate for more information.
1618
*
@@ -51,8 +53,9 @@ function aggregate(db, coll, pipeline, options, callback) {
5153
}
5254

5355
const takesWriteConcern = topology.capabilities().commandsTakeWriteConcern;
56+
const ismaster = topology.lastIsMaster() || {};
5457

55-
if (!hasOutStage) {
58+
if (!hasOutStage || ismaster.maxWireVersion >= MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT) {
5659
decorateWithReadConcern(command, target, options);
5760
}
5861

test/functional/readconcern_tests.js

+59-1
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ describe('ReadConcern', function() {
435435
});
436436

437437
it('Should set majority readConcern aggregate command but ignore due to out', {
438-
metadata: { requires: { topology: 'replicaset', mongodb: '>= 3.2' } },
438+
metadata: { requires: { topology: 'replicaset', mongodb: '>= 3.2 < 4.1' } },
439439

440440
test: function(done) {
441441
var listener = require('../..').instrument(function(err) {
@@ -500,6 +500,64 @@ describe('ReadConcern', function() {
500500
}
501501
});
502502

503+
it('Should set majority readConcern aggregate command against server >= 4.1', {
504+
metadata: { requires: { topology: 'replicaset', mongodb: '>= 4.1' } },
505+
506+
test: function(done) {
507+
// Contains all the apm events
508+
const started = [];
509+
const succeeded = [];
510+
// Get a new instance
511+
const client = this.configuration.newClient(
512+
{ w: 1 },
513+
{ poolSize: 1, readConcern: { level: 'majority' }, monitorCommands: true }
514+
);
515+
516+
client
517+
.connect()
518+
.then(() => {
519+
// Get a collection
520+
const collection = client
521+
.db(this.configuration.db)
522+
.collection('readConcernCollectionAggregate1');
523+
524+
// Listen to apm events
525+
client.on('commandStarted', event => {
526+
if (event.commandName === 'aggregate') started.push(event);
527+
});
528+
client.on('commandSucceeded', event => {
529+
if (event.commandName === 'aggregate') succeeded.push(event);
530+
});
531+
532+
// Execute find
533+
return collection
534+
.aggregate([{ $match: {} }, { $out: 'readConcernCollectionAggregate1Output' }])
535+
.toArray()
536+
.then(() => {
537+
expect(started).to.have.a.lengthOf(1);
538+
expect(started[0]).to.have.property('commandName', 'aggregate');
539+
expect(succeeded[0]).to.have.property('commandName', 'aggregate');
540+
expect(started[0]).to.have.nested.property('command.readConcern.level', 'majority');
541+
542+
// Execute find
543+
return collection
544+
.aggregate([{ $match: {} }], { out: 'readConcernCollectionAggregate2Output' })
545+
.toArray()
546+
.then(() => {
547+
expect(started).to.have.a.lengthOf(2);
548+
expect(started[1]).to.have.property('commandName', 'aggregate');
549+
expect(succeeded[1]).to.have.property('commandName', 'aggregate');
550+
expect(started[1]).to.have.nested.property(
551+
'command.readConcern.level',
552+
'majority'
553+
);
554+
});
555+
});
556+
})
557+
.then(() => client.close(done), e => client.close(() => done(e)));
558+
}
559+
});
560+
503561
it('Should set majority readConcern mapReduce command but be ignored', {
504562
metadata: { requires: { topology: 'replicaset', mongodb: '>= 3.2' } },
505563

0 commit comments

Comments
 (0)