Skip to content

Commit

Permalink
perf(model): skip $toObject() for insertMany with only primitive values
Browse files Browse the repository at this point in the history
Re: #14719
  • Loading branch information
vkarpov15 committed Jul 9, 2024
1 parent a860270 commit b698c28
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 27 deletions.
63 changes: 37 additions & 26 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -3811,13 +3811,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
Document.prototype.$toObject = function(options, json) {
const defaultOptions = this.$__schema._defaultToObjectOptions(json);

const hasOnlyPrimitiveValues = !this.$__.populated && !this.$__.wasPopulated && (this._doc == null || Object.values(this._doc).every(v => {
return v == null
|| typeof v !== 'object'
|| (utils.isNativeObject(v) && !Array.isArray(v))
|| isBsonType(v, 'ObjectId')
|| isBsonType(v, 'Decimal128');
}));
const hasOnlyPrimitiveValues = this.$__hasOnlyPrimitiveValues();

// If options do not exist or is not an object, set it to empty object
options = utils.isPOJO(options) ? { ...options } : {};
Expand Down Expand Up @@ -3867,27 +3861,10 @@ Document.prototype.$toObject = function(options, json) {
// const originalTransform = options.transform;

let ret;
if (hasOnlyPrimitiveValues) {
if (hasOnlyPrimitiveValues && !options.flattenObjectIds) {
// Fast path: if we don't have any nested objects or arrays, we only need a
// shallow clone.
if (this._doc == null) {
ret = {};
}
ret = {};
if (this._doc != null) {
for (const key of Object.keys(this._doc)) {
const value = this._doc[key];
if (value instanceof Date) {
ret[key] = new Date(value);
} else if (value === undefined) {
delete ret[key];
} else if (options.flattenObjectIds && isBsonType(value, 'ObjectId')) {
ret[key] = value.toJSON();
} else {
ret[key] = value;
}
}
}
ret = this.$__toObjectInternal();
} else {
ret = clone(this._doc, options) || {};
}
Expand Down Expand Up @@ -3948,6 +3925,26 @@ Document.prototype.$toObject = function(options, json) {
return ret;
};

/*!
* Internal shallow clone alternative to `$toObject()`: much faster, no options processing
*/

Document.prototype.$__toObjectInternal = function $__toObjectInternal() {
const ret = {};
if (this._doc != null) {
for (const key of Object.keys(this._doc)) {
const value = this._doc[key];
if (value instanceof Date) {
ret[key] = new Date(value);
} else if (value !== undefined) {
ret[key] = value;
}
}
}

return ret;
};

/**
* Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)).
*
Expand Down Expand Up @@ -5328,6 +5325,20 @@ Document.prototype.$clearModifiedPaths = function $clearModifiedPaths() {
return this;
};

/*!
* Check if the given document only has primitive values
*/

Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValues() {
return !this.$__.populated && !this.$__.wasPopulated && (this._doc == null || Object.values(this._doc).every(v => {
return v == null
|| typeof v !== 'object'
|| (utils.isNativeObject(v) && !Array.isArray(v))
|| isBsonType(v, 'ObjectId')
|| isBsonType(v, 'Decimal128');
}));
};

/*!
* Module exports.
*/
Expand Down
5 changes: 4 additions & 1 deletion lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2951,7 +2951,10 @@ Model.$__insertMany = function(arr, options, callback) {
}
const shouldSetTimestamps = (!options || options.timestamps !== false) && doc.initializeTimestamps && (!doc.$__ || doc.$__.timestamps !== false);
if (shouldSetTimestamps) {
return doc.initializeTimestamps().toObject(internalToObjectOptions);
doc.initializeTimestamps();
}
if (doc.$__hasOnlyPrimitiveValues()) {
return doc.$__toObjectInternal();
}
return doc.toObject(internalToObjectOptions);
});
Expand Down

0 comments on commit b698c28

Please sign in to comment.