Skip to content

Commit 05055f0

Browse files
authored
Merge pull request #14833 from Automattic/vkarpov15/gh-14827
fix(populate): fix a couple of other places where we get the document's _id with getters
2 parents be403ff + 9526e66 commit 05055f0

11 files changed

+71
-16
lines changed

lib/document.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ function init(self, obj, doc, opts, prefix) {
842842
*/
843843

844844
Document.prototype.updateOne = function updateOne(doc, options, callback) {
845-
const query = this.constructor.updateOne({ _id: this._id }, doc, options);
845+
const query = this.constructor.updateOne({ _id: this._doc._id }, doc, options);
846846
const self = this;
847847
query.pre(function queryPreUpdateOne(cb) {
848848
self.constructor._middleware.execPre('updateOne', self, [self], cb);
@@ -883,7 +883,7 @@ Document.prototype.updateOne = function updateOne(doc, options, callback) {
883883

884884
Document.prototype.replaceOne = function replaceOne() {
885885
const args = [...arguments];
886-
args.unshift({ _id: this._id });
886+
args.unshift({ _id: this._doc._id });
887887
return this.constructor.replaceOne.apply(this.constructor, args);
888888
};
889889

@@ -3050,7 +3050,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
30503050
} else if (val != null && val.$__ != null && val.$__.wasPopulated) {
30513051
// Array paths, like `somearray.1`, do not show up as populated with `$populated()`,
30523052
// so in that case pull out the document's id
3053-
val = val._id;
3053+
val = val._doc._id;
30543054
}
30553055
const scope = _this.$__.pathsToScopes != null && path in _this.$__.pathsToScopes ?
30563056
_this.$__.pathsToScopes[path] :

lib/error/parallelSave.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ParallelSaveError extends MongooseError {
1515
*/
1616
constructor(doc) {
1717
const msg = 'Can\'t save() the same doc multiple times in parallel. Document: ';
18-
super(msg + doc._id);
18+
super(msg + doc._doc._id);
1919
}
2020
}
2121

lib/error/parallelValidate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ParallelValidateError extends MongooseError {
1616
*/
1717
constructor(doc) {
1818
const msg = 'Can\'t validate() the same doc multiple times in parallel. Document: ';
19-
super(msg + doc._id);
19+
super(msg + doc._doc._id);
2020
}
2121
}
2222

lib/error/version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class VersionError extends MongooseError {
1717
*/
1818
constructor(doc, currentVersion, modifiedPaths) {
1919
const modifiedPathsStr = modifiedPaths.join(', ');
20-
super('No matching document found for id "' + doc._id +
20+
super('No matching document found for id "' + doc._doc._id +
2121
'" version ' + currentVersion + ' modifiedPaths "' + modifiedPathsStr + '"');
2222
this.version = currentVersion;
2323
this.modifiedPaths = modifiedPaths;

lib/helpers/model/discriminator.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
115115
}
116116
}
117117

118+
// Shallow clone `obj` so we can add additional properties without modifying original
119+
// schema. `Schema.prototype.clone()` copies `obj` by reference, no cloning.
120+
schema.obj = { ...schema.obj };
118121
mergeDiscriminatorSchema(schema, baseSchema);
119122

120123
// Clean up conflicting paths _after_ merging re: gh-6076

lib/helpers/populate/getModelsMapForPopulate.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ function _getLocalFieldValues(doc, localField, model, options, virtual, schema)
626626

627627
function convertTo_id(val, schema) {
628628
if (val != null && val.$__ != null) {
629-
return val._id;
629+
return val._doc._id;
630630
}
631631
if (val != null && val._id != null && (schema == null || !schema.$isSchemaMap)) {
632632
return val._id;
@@ -636,7 +636,7 @@ function convertTo_id(val, schema) {
636636
const rawVal = val.__array != null ? val.__array : val;
637637
for (let i = 0; i < rawVal.length; ++i) {
638638
if (rawVal[i] != null && rawVal[i].$__ != null) {
639-
rawVal[i] = rawVal[i]._id;
639+
rawVal[i] = rawVal[i]._doc._id;
640640
}
641641
}
642642
if (utils.isMongooseArray(val) && val.$schema()) {

lib/helpers/populate/markArraySubdocsPopulated.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ const utils = require('../../utils');
1717
*/
1818

1919
module.exports = function markArraySubdocsPopulated(doc, populated) {
20-
if (doc._id == null || populated == null || populated.length === 0) {
20+
if (doc._doc._id == null || populated == null || populated.length === 0) {
2121
return;
2222
}
2323

24-
const id = String(doc._id);
24+
const id = String(doc._doc._id);
2525
for (const item of populated) {
2626
if (item.isVirtual) {
2727
continue;

lib/model.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,7 +2345,7 @@ Model.findByIdAndUpdate = function(id, update, options) {
23452345

23462346
// if a model is passed in instead of an id
23472347
if (id instanceof Document) {
2348-
id = id._id;
2348+
id = id._doc._id;
23492349
}
23502350

23512351
return this.findOneAndUpdate.call(this, { _id: id }, update, options);
@@ -3408,7 +3408,7 @@ Model.bulkSave = async function bulkSave(documents, options) {
34083408
documents.map(async(document) => {
34093409
const documentError = bulkWriteError && bulkWriteError.writeErrors.find(writeError => {
34103410
const writeErrorDocumentId = writeError.err.op._id || writeError.err.op.q._id;
3411-
return writeErrorDocumentId.toString() === document._id.toString();
3411+
return writeErrorDocumentId.toString() === document._doc._id.toString();
34123412
});
34133413

34143414
if (documentError == null) {
@@ -4436,7 +4436,7 @@ function _assign(model, vals, mod, assignmentOpts) {
44364436

44374437
for (let __val of _val) {
44384438
if (__val instanceof Document) {
4439-
__val = __val._id;
4439+
__val = __val._doc._id;
44404440
}
44414441
key = String(__val);
44424442
if (rawDocs[key]) {

lib/query.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3380,9 +3380,9 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
33803380
if (!this._update || Object.keys(this._update).length === 0) {
33813381
if (options.upsert) {
33823382
// still need to do the upsert to empty doc
3383-
const doc = clone(this._update);
3384-
delete doc._id;
3385-
this._update = { $set: doc };
3383+
const $set = clone(this._update);
3384+
delete $set._id;
3385+
this._update = { $set };
33863386
} else {
33873387
this._executionStack = null;
33883388
const res = await this._findOne();

test/model.discriminator.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,23 @@ describe('model', function() {
620620
Person.discriminator('Parent2', parentSchema.clone());
621621
});
622622

623+
it('clone() does not modify original schema `obj` (gh-14821)', function() {
624+
const personSchema = new Schema({
625+
name: String
626+
}, { discriminatorKey: 'kind' });
627+
628+
const parentSchema = new Schema({
629+
child: String
630+
});
631+
632+
const Person = db.model('Person', personSchema);
633+
const Parent = Person.discriminator('Parent', parentSchema.clone());
634+
635+
assert.ok(!Person.schema.obj.child);
636+
assert.ok(!personSchema.obj.child);
637+
assert.ok(Parent.schema.obj.child);
638+
});
639+
623640
it('clone() allows reusing with different models (gh-5721)', async function() {
624641
const schema = new mongoose.Schema({
625642
name: String

0 commit comments

Comments
 (0)