Skip to content

Commit 1a998e2

Browse files
authored
Merge pull request #13588 from Automattic/vkarpov15/gh-13575
fix(populate): correctly set `populatedModelSymbol` on documents populated using `Model.populate()`
2 parents b336ed8 + 22b1e25 commit 1a998e2

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

lib/helpers/populate/getModelsMapForPopulate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ function addModelNamesToMap(model, map, available, modelNames, options, data, re
540540
// Used internally for checking what model was used to populate this
541541
// path.
542542
options[populateModelSymbol] = Model;
543+
currentOptions[populateModelSymbol] = Model;
543544
available[modelName] = {
544545
model: Model,
545546
options: currentOptions,

lib/model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4267,7 +4267,7 @@ const excludeIdReg = /\s?-_id\s?/;
42674267
const excludeIdRegGlobal = /\s?-_id\s?/g;
42684268

42694269
function populate(model, docs, options, callback) {
4270-
const populateOptions = { ...options };
4270+
const populateOptions = options;
42714271
if (options.strictPopulate == null) {
42724272
if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) {
42734273
populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate;

lib/types/array/methods/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ const methods = {
226226
if (populated && value !== null && value !== undefined) {
227227
// cast to the populated Models schema
228228
Model = populated.options[populateModelSymbol];
229+
if (Model == null) {
230+
throw new MongooseError('No populated model found for path `' + this[arrayPathSymbol] + '`. This is likely a bug in Mongoose, please report an issue on github.com/Automattic/mongoose.');
231+
}
229232

230233
// only objects are permitted so we can safely assume that
231234
// non-objects are to be interpreted as _id

test/model.populate.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10504,4 +10504,39 @@ describe('model: populate:', function() {
1050410504
});
1050510505
assert.deepStrictEqual(doc.children.map(c => c.name).sort(), ['Chad', 'Luke']);
1050610506
});
10507+
10508+
it('allows pushing to model populated in a query cursor (gh-13575)', async function() {
10509+
const Company = db.model('Company', Schema({ name: String }));
10510+
const User = db.model(
10511+
'User',
10512+
Schema({ name: String, companies: [{ type: Schema.Types.ObjectId, ref: 'Company' }] })
10513+
);
10514+
10515+
await User.deleteMany({});
10516+
await Company.insertMany([{ name: 'Company 1' }, { name: 'Company 2' }]);
10517+
const company = await Company.findOne({ name: 'Company 1' });
10518+
const company2 = await Company.findOne({ name: 'Company 2' });
10519+
10520+
await User.insertMany([{ name: 'User 1', companies: [company.id] }]);
10521+
10522+
await User.find()
10523+
.populate('companies')
10524+
.cursor()
10525+
.eachAsync(async(user) => {
10526+
if (!user.populated('companies')) {
10527+
await user.populate('companies');
10528+
}
10529+
10530+
user.companies.push(company2);
10531+
10532+
await user.save();
10533+
});
10534+
10535+
const user = await User.findOne();
10536+
assert.equal(user.name, 'User 1');
10537+
assert.deepEqual(
10538+
user.toObject().companies.sort().map(v => v.toString()),
10539+
[company._id.toString(), company2._id.toString()]
10540+
);
10541+
});
1050710542
});

0 commit comments

Comments
 (0)