Skip to content

Commit d333d8e

Browse files
authored
Merge pull request #15567 from Automattic/vkarpov15/gh-15553
fix(query): propagate read preference to populate if `read()` called after `populate()`
2 parents 8ece7d7 + c05baa5 commit d333d8e

File tree

3 files changed

+69
-18
lines changed

3 files changed

+69
-18
lines changed

lib/query.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,29 @@ Query.prototype._optionsForExec = function(model) {
21332133
}
21342134
}
21352135

2136+
if (this._mongooseOptions.populate) {
2137+
if (options.readPreference) {
2138+
for (const pop of Object.values(this._mongooseOptions.populate)) {
2139+
if (pop.options?.readPreference === undefined) {
2140+
if (!pop.options) {
2141+
pop.options = {};
2142+
}
2143+
pop.options.readPreference = options.readPreference;
2144+
}
2145+
}
2146+
}
2147+
if (options.readConcern) {
2148+
for (const pop of Object.values(this._mongooseOptions.populate)) {
2149+
if (pop.options?.readConcern === undefined) {
2150+
if (!pop.options) {
2151+
pop.options = {};
2152+
}
2153+
pop.options.readConcern = options.readConcern;
2154+
}
2155+
}
2156+
}
2157+
}
2158+
21362159
return options;
21372160
};
21382161

@@ -4918,24 +4941,6 @@ Query.prototype.populate = function() {
49184941

49194942
const res = utils.populate.apply(null, args);
49204943

4921-
// Propagate readConcern and readPreference and lean from parent query,
4922-
// unless one already specified
4923-
if (this.options != null) {
4924-
const readConcern = this.options.readConcern;
4925-
const readPref = this.options.readPreference;
4926-
4927-
for (const populateOptions of res) {
4928-
if (readConcern != null && (populateOptions && populateOptions.options && populateOptions.options.readConcern) == null) {
4929-
populateOptions.options = populateOptions.options || {};
4930-
populateOptions.options.readConcern = readConcern;
4931-
}
4932-
if (readPref != null && (populateOptions && populateOptions.options && populateOptions.options.readPreference) == null) {
4933-
populateOptions.options = populateOptions.options || {};
4934-
populateOptions.options.readPreference = readPref;
4935-
}
4936-
}
4937-
}
4938-
49394944
const opts = this._mongooseOptions;
49404945

49414946
if (opts.lean != null) {

test/model.populate.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5569,6 +5569,7 @@ describe('model: populate:', function() {
55695569
const Model = db.model('Test1', schema);
55705570

55715571
const q = Model.find().read('secondaryPreferred').populate('ref');
5572+
await q.exec();
55725573
assert.equal(q._mongooseOptions.populate['ref'].options.readPreference.mode,
55735574
'secondaryPreferred');
55745575
});

test/query.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4469,6 +4469,51 @@ describe('Query', function() {
44694469
});
44704470
});
44714471

4472+
it('propagates readPreference to populate options if read() is called after populate() (gh-15553)', async function() {
4473+
const schema = new Schema({ name: String, age: Number, friends: [{ type: 'ObjectId', ref: 'Person' }] });
4474+
const Person = db.model('Person', schema);
4475+
4476+
let query = Person.find({}).populate('friends');
4477+
query.read('secondaryPreferred');
4478+
await query.exec();
4479+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readPreference.mode, 'secondaryPreferred');
4480+
4481+
query = Person.find({}).read('secondary').populate('friends');
4482+
query.read('secondaryPreferred');
4483+
await query.exec();
4484+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readPreference.mode, 'secondaryPreferred');
4485+
4486+
query = Person.find({}).read('secondaryPreferred').populate('friends');
4487+
await query.exec();
4488+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readPreference.mode, 'secondaryPreferred');
4489+
4490+
query = Person.find({}).read('primaryPreferred').populate({ path: 'friends', options: { readPreference: 'secondaryPreferred' } });
4491+
await query.exec();
4492+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readPreference, 'secondaryPreferred');
4493+
});
4494+
4495+
it('propagates readConcern to populate options if readConcern() is called after populate() (gh-15553)', async function() {
4496+
const schema = new Schema({ name: String, age: Number, friends: [{ type: 'ObjectId', ref: 'Person' }] });
4497+
const Person = db.model('Person', schema);
4498+
4499+
let query = Person.find({}).populate('friends');
4500+
query.readConcern('majority');
4501+
await query.exec();
4502+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readConcern.level, 'majority');
4503+
4504+
query = Person.find({}).readConcern('local').populate('friends');
4505+
query.readConcern('majority');
4506+
await query.exec();
4507+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readConcern.level, 'majority');
4508+
4509+
query = Person.find({}).readConcern('majority').populate('friends');
4510+
await query.exec();
4511+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readConcern.level, 'majority');
4512+
4513+
query = Person.find({}).readConcern('majority').populate({ path: 'friends', options: { readConcern: 'local' } });
4514+
await query.exec();
4515+
assert.strictEqual(query._mongooseOptions.populate.friends.options.readConcern, 'local');
4516+
});
44724517

44734518
describe('Query with requireFilter', function() {
44744519
let Person;

0 commit comments

Comments
 (0)