Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More toObject() perf improvements #14623

Merged
merged 10 commits into from
Jun 2, 2024
Prev Previous commit
Next Next commit
perf: memoize default toObject options on a per-schema basis re: #14394
vkarpov15 committed May 31, 2024
commit 75c6f8887901be602ca2291ef3d2ffd57b076507
21 changes: 2 additions & 19 deletions lib/document.js
Original file line number Diff line number Diff line change
@@ -22,7 +22,6 @@ const clone = require('./helpers/clone');
const compile = require('./helpers/document/compile').compile;
const defineKey = require('./helpers/document/compile').defineKey;
const flatten = require('./helpers/common').flatten;
const get = require('./helpers/get');
const getEmbeddedDiscriminatorPath = require('./helpers/document/getEmbeddedDiscriminatorPath');
const getKeysInSchemaOrder = require('./helpers/schema/getKeysInSchemaOrder');
const getSubdocumentStrictValue = require('./helpers/schema/getSubdocumentStrictValue');
@@ -3798,15 +3797,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
*/

Document.prototype.$toObject = function(options, json) {
const path = json ? 'toJSON' : 'toObject';
const baseOptions = this.constructor &&
this.constructor.base &&
this.constructor.base.options &&
get(this.constructor.base.options, path) || {};
const schemaOptions = this.$__schema && this.$__schema.options || {};
// merge base default options with Schema's set default options if available.
// `clone` is necessary here because `utils.options` directly modifies the second input.
const defaultOptions = Object.assign({}, baseOptions, schemaOptions[path]);
const defaultOptions = this.$__schema._getDefaultToObjectOptions();

// If options do not exist or is not an object, set it to empty object
options = utils.isPOJO(options) ? { ...options } : {};
@@ -3815,10 +3806,8 @@ Document.prototype.$toObject = function(options, json) {
let _minimize;
if (options._calledWithOptions.minimize != null) {
_minimize = options.minimize;
} else if (defaultOptions.minimize != null) {
_minimize = defaultOptions.minimize;
} else {
_minimize = schemaOptions.minimize;
_minimize = defaultOptions.minimize;
}

options.minimize = _minimize;
@@ -3842,14 +3831,8 @@ Document.prototype.$toObject = function(options, json) {
}
options._isNested = true;
options.json = json;
options.minimize = _minimize;

options._parentOptions = options;

options._skipSingleNestedGetters = false;
// remember the root transform function
// to save it from being overwritten by sub-transform functions
// const originalTransform = options.transform;

let ret = clone(this._doc, options) || {};

28 changes: 28 additions & 0 deletions lib/schema.js
Original file line number Diff line number Diff line change
@@ -128,6 +128,7 @@ function Schema(obj, options) {
// For internal debugging. Do not use this to try to save a schema in MDB.
this.$id = ++id;
this.mapPaths = [];
this._defaultToObjectOptions = null;

this.s = {
hooks: new Kareem()
@@ -2597,6 +2598,33 @@ Schema.prototype.loadClass = function(model, virtualsOnly) {
return this;
};

/**
* Returns default `toObject` / `toJSON` options for this schema,
* combining the associated
*
* @param {Boolean} json
* @returns object
*/

Schema.prototype._getDefaultToObjectOptions = function _getDefaultToObjectOptions(json) {
const path = json ? 'toJSON' : 'toObject';

if (this._defaultToObjectOptions && this._defaultToObjectOptions[path]) {
return this._defaultToObjectOptions[path];
}

const baseOptions = this.base && this.base.options && this.base.options[path];
const schemaOptions = this.options && this.options[path];
const defaultOptions = Object.assign(
{},
baseOptions,
schemaOptions
);
this._defaultToObjectOptions = this._defaultToObjectOptions || {};
this._defaultToObjectOptions[path] = defaultOptions;
return defaultOptions;
};

/*!
* ignore
*/