From 31104f827ca6fcb9913a58ad2c94c5c52ced0b65 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 6 Nov 2024 16:55:11 -0500 Subject: [PATCH 1/3] perf: make a few micro-optimizations to help speed up findOne() Re: #14906 --- lib/helpers/isBsonType.js | 3 +-- lib/helpers/schema/applyReadConcern.js | 4 +--- lib/helpers/schema/applyWriteConcern.js | 4 +--- lib/query.js | 24 +++++++++++++----------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/lib/helpers/isBsonType.js b/lib/helpers/isBsonType.js index f75fd40169d..ab6ceba58e6 100644 --- a/lib/helpers/isBsonType.js +++ b/lib/helpers/isBsonType.js @@ -7,8 +7,7 @@ function isBsonType(obj, typename) { return ( - typeof obj === 'object' && - obj !== null && + obj != null && obj._bsontype === typename ); } diff --git a/lib/helpers/schema/applyReadConcern.js b/lib/helpers/schema/applyReadConcern.js index 80d4da6eb20..050fa9c6df0 100644 --- a/lib/helpers/schema/applyReadConcern.js +++ b/lib/helpers/schema/applyReadConcern.js @@ -1,7 +1,5 @@ 'use strict'; -const get = require('../get'); - module.exports = function applyReadConcern(schema, options) { if (options.readConcern !== undefined) { return; @@ -15,7 +13,7 @@ module.exports = function applyReadConcern(schema, options) { return; } - const level = get(schema, 'options.readConcern.level', null); + const level = schema.options?.readConcern?.level; if (level != null) { options.readConcern = { level }; } diff --git a/lib/helpers/schema/applyWriteConcern.js b/lib/helpers/schema/applyWriteConcern.js index 27098110872..28338cf58c3 100644 --- a/lib/helpers/schema/applyWriteConcern.js +++ b/lib/helpers/schema/applyWriteConcern.js @@ -1,7 +1,5 @@ 'use strict'; -const get = require('../get'); - module.exports = function applyWriteConcern(schema, options) { if (options.writeConcern != null) { return; @@ -12,7 +10,7 @@ module.exports = function applyWriteConcern(schema, options) { if (options && options.session && options.session.transaction) { return; } - const writeConcern = get(schema, 'options.writeConcern', {}); + const writeConcern = schema.options.writeConcern ?? {}; if (Object.keys(writeConcern).length != 0) { options.writeConcern = {}; if (!('w' in options) && writeConcern.w != null) { diff --git a/lib/query.js b/lib/query.js index 6333c153c68..ff86fa9389a 100644 --- a/lib/query.js +++ b/lib/query.js @@ -2248,6 +2248,9 @@ Query.prototype.error = function error(err) { */ Query.prototype._unsetCastError = function _unsetCastError() { + if (this._error == null) { + return; + } if (this._error != null && !(this._error instanceof CastError)) { return; } @@ -2291,9 +2294,9 @@ Query.prototype.mongooseOptions = function(v) { Query.prototype._castConditions = function() { let sanitizeFilterOpt = undefined; - if (this.model != null && utils.hasUserDefinedProperty(this.model.db.options, 'sanitizeFilter')) { + if (this.model != null && this.model.db.options?.sanitizeFilter != null) { sanitizeFilterOpt = this.model.db.options.sanitizeFilter; - } else if (this.model != null && utils.hasUserDefinedProperty(this.model.base.options, 'sanitizeFilter')) { + } else if (this.model != null && this.model.base.options?.sanitizeFilter != null) { sanitizeFilterOpt = this.model.base.options.sanitizeFilter; } else { sanitizeFilterOpt = this._mongooseOptions.sanitizeFilter; @@ -2536,13 +2539,12 @@ Query.prototype.collation = function(value) { * @api private */ -Query.prototype._completeOne = function(doc, res, callback) { +Query.prototype._completeOne = function(doc, res, projection, callback) { if (!doc && !this.options.includeResultMetadata) { return callback(null, null); } const model = this.model; - const projection = clone(this._fields); const userProvidedFields = this._userProvidedFields || {}; // `populate`, `lean` const mongooseOptions = this._mongooseOptions; @@ -2643,7 +2645,7 @@ Query.prototype._findOne = async function _findOne() { // don't pass in the conditions because we already merged them in const doc = await this.mongooseCollection.findOne(this._conditions, options); return new Promise((resolve, reject) => { - this._completeOne(doc, null, (err, res) => { + this._completeOne(doc, null, options.projection, (err, res) => { if (err) { return reject(err); } @@ -3238,7 +3240,7 @@ function completeOne(model, doc, res, options, fields, userProvidedFields, pop, function _init(err, casted) { if (err) { - return immediate(() => callback(err)); + return callback(err); } @@ -3251,12 +3253,12 @@ function completeOne(model, doc, res, options, fields, userProvidedFields, pop, } else { res.value = null; } - return immediate(() => callback(null, res)); + return callback(null, res); } if (options.session != null) { casted.$session(options.session); } - immediate(() => callback(null, casted)); + callback(null, casted); } } @@ -3465,7 +3467,7 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() { const doc = !options.includeResultMetadata ? res : res.value; return new Promise((resolve, reject) => { - this._completeOne(doc, res, (err, res) => { + this._completeOne(doc, res, options.projection, (err, res) => { if (err) { return reject(err); } @@ -3561,7 +3563,7 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() { const doc = !includeResultMetadata ? res : res.value; return new Promise((resolve, reject) => { - this._completeOne(doc, res, (err, res) => { + this._completeOne(doc, res, options.projection, (err, res) => { if (err) { return reject(err); } @@ -3715,7 +3717,7 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() { const doc = !includeResultMetadata ? res : res.value; return new Promise((resolve, reject) => { - this._completeOne(doc, res, (err, res) => { + this._completeOne(doc, res, options.projection, (err, res) => { if (err) { return reject(err); } From 9f4def3fe6e44f3c2536a32f83021d365dbd5407 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 6 Nov 2024 17:02:53 -0500 Subject: [PATCH 2/3] fix lint --- lib/query.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/query.js b/lib/query.js index ff86fa9389a..212cffd7949 100644 --- a/lib/query.js +++ b/lib/query.js @@ -22,7 +22,6 @@ const castUpdate = require('./helpers/query/castUpdate'); const clone = require('./helpers/clone'); const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue'); const helpers = require('./queryHelpers'); -const immediate = require('./helpers/immediate'); const internalToObjectOptions = require('./options').internalToObjectOptions; const isExclusive = require('./helpers/projection/isExclusive'); const isInclusive = require('./helpers/projection/isInclusive'); From e40a09064bfd8cfcc99008a601f001c91684d4c3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 7 Nov 2024 09:36:51 -0500 Subject: [PATCH 3/3] address code review comments --- lib/query.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/query.js b/lib/query.js index 212cffd7949..99a67d55ddb 100644 --- a/lib/query.js +++ b/lib/query.js @@ -2293,9 +2293,9 @@ Query.prototype.mongooseOptions = function(v) { Query.prototype._castConditions = function() { let sanitizeFilterOpt = undefined; - if (this.model != null && this.model.db.options?.sanitizeFilter != null) { + if (this.model?.db.options?.sanitizeFilter != null) { sanitizeFilterOpt = this.model.db.options.sanitizeFilter; - } else if (this.model != null && this.model.base.options?.sanitizeFilter != null) { + } else if (this.model?.base.options?.sanitizeFilter != null) { sanitizeFilterOpt = this.model.base.options.sanitizeFilter; } else { sanitizeFilterOpt = this._mongooseOptions.sanitizeFilter;