Skip to content

Commit 328ddaa

Browse files
committed
fix(document): avoid massive perf degradation when saving new doc with 10 level deep subdocs
Fix Automattic#14897
1 parent f9ca745 commit 328ddaa

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

lib/document.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2724,7 +2724,9 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
27242724
}
27252725

27262726
if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2727-
!doc.isDirectModified(fullPathToSubdoc) &&
2727+
// Avoid using isDirectModified() here because that does additional checks on whether the parent path
2728+
// is direct modified, which can cause performance issues re: gh-14897
2729+
!doc.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
27282730
!doc.$isDefault(fullPathToSubdoc)) {
27292731
paths.add(fullPathToSubdoc);
27302732

test/document.test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13905,6 +13905,27 @@ describe('document', function() {
1390513905
const objectWithGetters = result.toObject({ getters: true, virtuals: false });
1390613906
assert.strictEqual(objectWithGetters.level1.level2.level3.property, 'TESTVALUE');
1390713907
});
13908+
13909+
it('handles inserting and saving large document with 10-level deep subdocs (gh-14897)', async function() {
13910+
const levels = 10;
13911+
13912+
let schema = new Schema({ test: { type: String, required: true } });
13913+
let doc = { test: 'gh-14897' };
13914+
for (let i = 0; i < levels; ++i) {
13915+
schema = new Schema({ level: Number, subdocs: [schema] });
13916+
doc = { level: (levels - i), subdocs: [{ ...doc }, { ...doc }] };
13917+
}
13918+
13919+
const Test = db.model('Test', schema);
13920+
const savedDoc = await Test.create(doc);
13921+
13922+
let cur = savedDoc;
13923+
for (let i = 0; i < levels - 1; ++i) {
13924+
cur = cur.subdocs[0];
13925+
}
13926+
cur.subdocs[0] = { test: 'updated' };
13927+
await savedDoc.save();
13928+
});
1390813929
});
1390913930

1391013931
describe('Check if instance function that is supplied in schema option is available', function() {

0 commit comments

Comments
 (0)