Skip to content

Commit b698c28

Browse files
committed
perf(model): skip $toObject() for insertMany with only primitive values
Re: #14719
1 parent a860270 commit b698c28

File tree

2 files changed

+41
-27
lines changed

2 files changed

+41
-27
lines changed

lib/document.js

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3811,13 +3811,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
38113811
Document.prototype.$toObject = function(options, json) {
38123812
const defaultOptions = this.$__schema._defaultToObjectOptions(json);
38133813

3814-
const hasOnlyPrimitiveValues = !this.$__.populated && !this.$__.wasPopulated && (this._doc == null || Object.values(this._doc).every(v => {
3815-
return v == null
3816-
|| typeof v !== 'object'
3817-
|| (utils.isNativeObject(v) && !Array.isArray(v))
3818-
|| isBsonType(v, 'ObjectId')
3819-
|| isBsonType(v, 'Decimal128');
3820-
}));
3814+
const hasOnlyPrimitiveValues = this.$__hasOnlyPrimitiveValues();
38213815

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

38693863
let ret;
3870-
if (hasOnlyPrimitiveValues) {
3864+
if (hasOnlyPrimitiveValues && !options.flattenObjectIds) {
38713865
// Fast path: if we don't have any nested objects or arrays, we only need a
38723866
// shallow clone.
3873-
if (this._doc == null) {
3874-
ret = {};
3875-
}
3876-
ret = {};
3877-
if (this._doc != null) {
3878-
for (const key of Object.keys(this._doc)) {
3879-
const value = this._doc[key];
3880-
if (value instanceof Date) {
3881-
ret[key] = new Date(value);
3882-
} else if (value === undefined) {
3883-
delete ret[key];
3884-
} else if (options.flattenObjectIds && isBsonType(value, 'ObjectId')) {
3885-
ret[key] = value.toJSON();
3886-
} else {
3887-
ret[key] = value;
3888-
}
3889-
}
3890-
}
3867+
ret = this.$__toObjectInternal();
38913868
} else {
38923869
ret = clone(this._doc, options) || {};
38933870
}
@@ -3948,6 +3925,26 @@ Document.prototype.$toObject = function(options, json) {
39483925
return ret;
39493926
};
39503927

3928+
/*!
3929+
* Internal shallow clone alternative to `$toObject()`: much faster, no options processing
3930+
*/
3931+
3932+
Document.prototype.$__toObjectInternal = function $__toObjectInternal() {
3933+
const ret = {};
3934+
if (this._doc != null) {
3935+
for (const key of Object.keys(this._doc)) {
3936+
const value = this._doc[key];
3937+
if (value instanceof Date) {
3938+
ret[key] = new Date(value);
3939+
} else if (value !== undefined) {
3940+
ret[key] = value;
3941+
}
3942+
}
3943+
}
3944+
3945+
return ret;
3946+
};
3947+
39513948
/**
39523949
* Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)).
39533950
*
@@ -5328,6 +5325,20 @@ Document.prototype.$clearModifiedPaths = function $clearModifiedPaths() {
53285325
return this;
53295326
};
53305327

5328+
/*!
5329+
* Check if the given document only has primitive values
5330+
*/
5331+
5332+
Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValues() {
5333+
return !this.$__.populated && !this.$__.wasPopulated && (this._doc == null || Object.values(this._doc).every(v => {
5334+
return v == null
5335+
|| typeof v !== 'object'
5336+
|| (utils.isNativeObject(v) && !Array.isArray(v))
5337+
|| isBsonType(v, 'ObjectId')
5338+
|| isBsonType(v, 'Decimal128');
5339+
}));
5340+
};
5341+
53315342
/*!
53325343
* Module exports.
53335344
*/

lib/model.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2951,7 +2951,10 @@ Model.$__insertMany = function(arr, options, callback) {
29512951
}
29522952
const shouldSetTimestamps = (!options || options.timestamps !== false) && doc.initializeTimestamps && (!doc.$__ || doc.$__.timestamps !== false);
29532953
if (shouldSetTimestamps) {
2954-
return doc.initializeTimestamps().toObject(internalToObjectOptions);
2954+
doc.initializeTimestamps();
2955+
}
2956+
if (doc.$__hasOnlyPrimitiveValues()) {
2957+
return doc.$__toObjectInternal();
29552958
}
29562959
return doc.toObject(internalToObjectOptions);
29572960
});

0 commit comments

Comments
 (0)