Skip to content

Commit 13db408

Browse files
authored
Merge pull request #14565 from Automattic/vkarpov15/gh-14394
perf(document): avoid cloning options using spread operator for perf reasons
2 parents 3b00122 + 31596d5 commit 13db408

File tree

3 files changed

+20
-32
lines changed

3 files changed

+20
-32
lines changed

lib/document.js

+18-19
Original file line numberDiff line numberDiff line change
@@ -3780,7 +3780,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
37803780
*/
37813781

37823782
Document.prototype.$toObject = function(options, json) {
3783-
let defaultOptions = {
3783+
const defaultOptions = {
37843784
transform: true,
37853785
flattenDecimals: true
37863786
};
@@ -3793,7 +3793,7 @@ Document.prototype.$toObject = function(options, json) {
37933793
const schemaOptions = this.$__schema && this.$__schema.options || {};
37943794
// merge base default options with Schema's set default options if available.
37953795
// `clone` is necessary here because `utils.options` directly modifies the second input.
3796-
defaultOptions = { ...defaultOptions, ...baseOptions, ...schemaOptions[path] };
3796+
Object.assign(defaultOptions, baseOptions, schemaOptions[path]);
37973797

37983798
// If options do not exist or is not an object, set it to empty object
37993799
options = utils.isPOJO(options) ? { ...options } : {};
@@ -3830,21 +3830,18 @@ Document.prototype.$toObject = function(options, json) {
38303830
// `clone()` will recursively call `$toObject()` on embedded docs, so we
38313831
// need the original options the user passed in, plus `_isNested` and
38323832
// `_parentOptions` for checking whether we need to depopulate.
3833-
const cloneOptions = Object.assign({}, options, {
3833+
const cloneOptions = {
38343834
_isNested: true,
38353835
json: json,
38363836
minimize: _minimize,
38373837
flattenMaps: flattenMaps,
38383838
flattenObjectIds: flattenObjectIds,
3839-
_seen: (options && options._seen) || new Map()
3840-
});
3841-
3842-
if (utils.hasUserDefinedProperty(options, 'getters')) {
3843-
cloneOptions.getters = options.getters;
3844-
}
3845-
if (utils.hasUserDefinedProperty(options, 'virtuals')) {
3846-
cloneOptions.virtuals = options.virtuals;
3847-
}
3839+
_seen: (options && options._seen) || new Map(),
3840+
_calledWithOptions: options._calledWithOptions,
3841+
virtuals: options.virtuals,
3842+
getters: options.getters,
3843+
depopulate: options.depopulate
3844+
};
38483845

38493846
const depopulate = options.depopulate ||
38503847
(options._parentOptions && options._parentOptions.depopulate || false);
@@ -3855,33 +3852,35 @@ Document.prototype.$toObject = function(options, json) {
38553852
}
38563853

38573854
// merge default options with input options.
3858-
options = { ...defaultOptions, ...options };
3855+
for (const key of Object.keys(defaultOptions)) {
3856+
if (options[key] == null) {
3857+
options[key] = defaultOptions[key];
3858+
}
3859+
}
38593860
options._isNested = true;
38603861
options.json = json;
38613862
options.minimize = _minimize;
38623863

38633864
cloneOptions._parentOptions = options;
3864-
cloneOptions._skipSingleNestedGetters = false;
3865-
3866-
const gettersOptions = Object.assign({}, cloneOptions);
3867-
gettersOptions._skipSingleNestedGetters = true;
38683865

3866+
cloneOptions._skipSingleNestedGetters = false;
38693867
// remember the root transform function
38703868
// to save it from being overwritten by sub-transform functions
38713869
const originalTransform = options.transform;
38723870

38733871
let ret = clone(this._doc, cloneOptions) || {};
38743872

3873+
cloneOptions._skipSingleNestedGetters = true;
38753874
if (options.getters) {
3876-
applyGetters(this, ret, gettersOptions);
3875+
applyGetters(this, ret, cloneOptions);
38773876

38783877
if (options.minimize) {
38793878
ret = minimize(ret) || {};
38803879
}
38813880
}
38823881

38833882
if (options.virtuals || (options.getters && options.virtuals !== false)) {
3884-
applyVirtuals(this, ret, gettersOptions, options);
3883+
applyVirtuals(this, ret, cloneOptions, options);
38853884
}
38863885

38873886
if (options.versionKey === false && this.$__schema.options.versionKey) {

test/document.test.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -722,32 +722,27 @@ describe('document', function() {
722722
lastName: String,
723723
password: String
724724
});
725-
726725
userSchema.virtual('fullName').get(function() {
727726
return this.firstName + ' ' + this.lastName;
728727
});
729-
730728
userSchema.set('toObject', { virtuals: false });
731729

732730
const postSchema = new Schema({
733731
owner: { type: Schema.Types.ObjectId, ref: 'User' },
734732
content: String
735733
});
736-
737734
postSchema.virtual('capContent').get(function() {
738735
return this.content.toUpperCase();
739736
});
740-
741737
postSchema.set('toObject', { virtuals: true });
738+
742739
const User = db.model('User', userSchema);
743740
const Post = db.model('BlogPost', postSchema);
744741

745742
const user = new User({ firstName: 'Joe', lastName: 'Smith', password: 'password' });
746-
747743
const savedUser = await user.save();
748744

749745
const post = await Post.create({ owner: savedUser._id, content: 'lorem ipsum' });
750-
751746
const newPost = await Post.findById(post._id).populate('owner').exec();
752747

753748
const obj = newPost.toObject();

test/model.populate.test.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -2976,33 +2976,27 @@ describe('model: populate:', function() {
29762976
return ret;
29772977
}
29782978
});
2979-
29802979
const Team = db.model('Test', teamSchema);
29812980

29822981
const userSchema = new Schema({
29832982
username: String
29842983
});
2985-
29862984
userSchema.set('toJSON', {
29872985
transform: function(doc, ret) {
29882986
return ret;
29892987
}
29902988
});
2991-
29922989
const User = db.model('User', userSchema);
29932990

29942991
const user = new User({ username: 'Test' });
2995-
29962992
await user.save();
29972993

29982994
const team = new Team({ members: [{ user: user }] });
2999-
30002995
await team.save();
3001-
30022996
await team.populate('members.user');
30032997

2998+
assert.equal(calls, 0);
30042999
team.toJSON();
3005-
30063000
assert.equal(calls, 1);
30073001
});
30083002

0 commit comments

Comments
 (0)