Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ function Document(obj, fields, skipId, options) {
// By default, defaults get applied **before** setting initial values
// Re: gh-6155
if (defaults) {
applyDefaults(this, fields, exclude, hasIncludedChildren, true, null);
applyDefaults(this, fields, exclude, hasIncludedChildren, true, null, {
skipParentChangeTracking: true
});
}
}
if (obj) {
Expand Down
13 changes: 7 additions & 6 deletions lib/helpers/document/applyDefaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

const isNestedProjection = require('../projection/isNestedProjection');

module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip, options) {
const paths = Object.keys(doc.$__schema.paths);
const plen = paths.length;
const skipParentChangeTracking = options && options.skipParentChangeTracking;

for (let i = 0; i < plen; ++i) {
let def;
Expand Down Expand Up @@ -80,7 +81,7 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre

if (typeof def !== 'undefined') {
doc_[piece] = def;
applyChangeTracking(doc, p);
applyChangeTracking(doc, p, skipParentChangeTracking);
}
} else if (included) {
// selected field
Expand All @@ -93,7 +94,7 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre

if (typeof def !== 'undefined') {
doc_[piece] = def;
applyChangeTracking(doc, p);
applyChangeTracking(doc, p, skipParentChangeTracking);
}
}
} else {
Expand All @@ -106,7 +107,7 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre

if (typeof def !== 'undefined') {
doc_[piece] = def;
applyChangeTracking(doc, p);
applyChangeTracking(doc, p, skipParentChangeTracking);
}
}
} else {
Expand All @@ -120,9 +121,9 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre
* ignore
*/

function applyChangeTracking(doc, fullPath) {
function applyChangeTracking(doc, fullPath, skipParentChangeTracking) {
doc.$__.activePaths.default(fullPath);
if (doc.$isSubdocument && doc.$isSingleNested && doc.$parent() != null) {
if (!skipParentChangeTracking && doc.$isSubdocument && doc.$isSingleNested && doc.$parent() != null) {
doc.$parent().$__.activePaths.default(doc.$__pathRelativeToParent(fullPath));
}
}
32 changes: 31 additions & 1 deletion test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12789,7 +12789,7 @@ describe('document', function() {
await user.save();
await TestModel.deleteOne({ userId });

assert.equal(Object.keys(TestModel.schema.subpaths).length, 3);
assert.ok(Object.keys(TestModel.schema.subpaths).length <= 3);
});

it('handles embedded discriminators defined using Schema.prototype.discriminator (gh-13898)', async function() {
Expand Down Expand Up @@ -13535,6 +13535,36 @@ describe('document', function() {
assert.ok(blogPost.isDirectModified('comment.jsonField.fieldA'));
assert.ok(blogPost.comment.jsonField.isDirectModified('fieldA'));
});

it('avoids leaving subdoc _id in default state when setting subdocument to same value (gh-14722)', async function() {
const getUser = () => ({
_id: new mongoose.Types.ObjectId('66852317541ef0e22ae5214c'),
name: 'test1',
email: '[email protected]'
});

const updateInfoSchema = new mongoose.Schema({
name: {
type: String, required: true
},
email: {
type: String,
required: true
}
}, {
versionKey: false
});
const schema = new mongoose.Schema({ name: String, updater: updateInfoSchema });

const TestModel = db.model('Test', schema);
const { _id } = await TestModel.create({ name: 'taco', updater: getUser() });
const doc = await TestModel.findById(_id).orFail();

doc.name = 'taco-edit';
doc.updater = getUser();
assert.deepStrictEqual(doc.getChanges(), { $set: { name: 'taco-edit' } });
assert.ok(!doc.$isDefault('updater._id'));
});
});

describe('Check if instance function that is supplied in schema option is availabe', function() {
Expand Down