From 090f23a75eaf45d050755b020879a65b4d7fc0b3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sat, 4 May 2024 07:29:05 -0400 Subject: [PATCH] fix(query): apply translateAliases before casting to avoid strictMode error when using aliases Fix #14521 --- lib/query.js | 29 ++++++++++++++--------------- test/query.test.js | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/lib/query.js b/lib/query.js index c0d44e020c9..22956fb818f 100644 --- a/lib/query.js +++ b/lib/query.js @@ -2222,6 +2222,7 @@ function _castArrayFilters(query) { * @api private */ Query.prototype._find = async function _find() { + this._applyTranslateAliases(); this._castConditions(); if (this.error() != null) { @@ -2244,8 +2245,6 @@ Query.prototype._find = async function _find() { const options = this._optionsForExec(); - this._applyTranslateAliases(options); - const filter = this._conditions; const fields = options.projection; @@ -2510,6 +2509,7 @@ Query.prototype._completeMany = async function _completeMany(docs, fields, userP */ Query.prototype._findOne = async function _findOne() { + this._applyTranslateAliases(); this._castConditions(); if (this.error()) { @@ -2522,8 +2522,6 @@ Query.prototype._findOne = async function _findOne() { const options = this._optionsForExec(); - this._applyTranslateAliases(options); - // 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) => { @@ -2604,6 +2602,8 @@ Query.prototype.findOne = function(conditions, projection, options) { */ Query.prototype._countDocuments = async function _countDocuments() { + this._applyTranslateAliases(); + try { this.cast(this.model); } catch (err) { @@ -2619,8 +2619,6 @@ Query.prototype._countDocuments = async function _countDocuments() { const options = this._optionsForExec(); - this._applyTranslateAliases(options); - const conds = this._conditions; return this.mongooseCollection.countDocuments(conds, options); @@ -2631,7 +2629,7 @@ Query.prototype._countDocuments = async function _countDocuments() { * on the following query properties: filter, projection, update, distinct. */ -Query.prototype._applyTranslateAliases = function _applyTranslateAliases(options) { +Query.prototype._applyTranslateAliases = function _applyTranslateAliases() { let applyTranslateAliases = false; if ('translateAliases' in this._mongooseOptions) { applyTranslateAliases = this._mongooseOptions.translateAliases; @@ -2646,7 +2644,7 @@ Query.prototype._applyTranslateAliases = function _applyTranslateAliases(options if (this.model?.schema?.aliases && Object.keys(this.model.schema.aliases).length > 0) { this.model.translateAliases(this._conditions, true); - this.model.translateAliases(options.projection, true); + this.model.translateAliases(this._fields, true); this.model.translateAliases(this._update, true); if (this._distinct != null && this.model.schema.aliases[this._distinct] != null) { this._distinct = this.model.schema.aliases[this._distinct]; @@ -2777,6 +2775,7 @@ Query.prototype.countDocuments = function(conditions, options) { */ Query.prototype.__distinct = async function __distinct() { + this._applyTranslateAliases(); this._castConditions(); if (this.error()) { @@ -2787,7 +2786,6 @@ Query.prototype.__distinct = async function __distinct() { applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options); const options = this._optionsForExec(); - this._applyTranslateAliases(options); return this.mongooseCollection. distinct(this._distinct, this._conditions, options); @@ -3006,6 +3004,7 @@ Query.prototype.deleteOne = function deleteOne(filter, options) { */ Query.prototype._deleteOne = async function _deleteOne() { + this._applyTranslateAliases(); this._castConditions(); if (this.error() != null) { @@ -3013,7 +3012,6 @@ Query.prototype._deleteOne = async function _deleteOne() { } const options = this._optionsForExec(); - this._applyTranslateAliases(options); return this.mongooseCollection.deleteOne(this._conditions, options); }; @@ -3080,6 +3078,7 @@ Query.prototype.deleteMany = function(filter, options) { */ Query.prototype._deleteMany = async function _deleteMany() { + this._applyTranslateAliases(); this._castConditions(); if (this.error() != null) { @@ -3087,7 +3086,6 @@ Query.prototype._deleteMany = async function _deleteMany() { } const options = this._optionsForExec(); - this._applyTranslateAliases(options); return this.mongooseCollection.deleteMany(this._conditions, options); }; @@ -3277,6 +3275,7 @@ Query.prototype.findOneAndUpdate = function(filter, doc, options) { */ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() { + this._applyTranslateAliases(); this._castConditions(); _castArrayFilters(this); @@ -3293,7 +3292,6 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() { } const options = this._optionsForExec(this.model); convertNewToReturnDocument(options); - this._applyTranslateAliases(options); this._update = this._castUpdate(this._update); @@ -3418,6 +3416,7 @@ Query.prototype.findOneAndDelete = function(filter, options) { * @api private */ Query.prototype._findOneAndDelete = async function _findOneAndDelete() { + this._applyTranslateAliases(); this._castConditions(); if (this.error() != null) { @@ -3428,7 +3427,6 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() { const filter = this._conditions; const options = this._optionsForExec(this.model); - this._applyTranslateAliases(options); let res = await this.mongooseCollection.findOneAndDelete(filter, options); for (const fn of this._transforms) { @@ -3542,6 +3540,7 @@ Query.prototype.findOneAndReplace = function(filter, replacement, options) { * @api private */ Query.prototype._findOneAndReplace = async function _findOneAndReplace() { + this._applyTranslateAliases(); this._castConditions(); if (this.error() != null) { throw this.error(); @@ -3554,7 +3553,6 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() { const filter = this._conditions; const options = this._optionsForExec(); - this._applyTranslateAliases(options); convertNewToReturnDocument(options); const includeResultMetadata = this.options.includeResultMetadata; @@ -3749,6 +3747,8 @@ Query.prototype._mergeUpdate = function(doc) { */ async function _updateThunk(op) { + this._applyTranslateAliases(); + this._castConditions(); _castArrayFilters(this); @@ -3759,7 +3759,6 @@ async function _updateThunk(op) { const castedQuery = this._conditions; const options = this._optionsForExec(this.model); - this._applyTranslateAliases(options); this._update = clone(this._update, options); const isOverwriting = op === 'replaceOne'; diff --git a/test/query.test.js b/test/query.test.js index 94f6911903a..21db30e8b3b 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -3718,6 +3718,28 @@ describe('Query', function() { }, /Provided object has both field "n" and its alias "name"/); }); + it('translateAliases applies before casting (gh-14521) (gh-7511)', async function() { + const testSchema = new Schema({ + name: { + type: String, + alias: 'n' + }, + age: { + type: Number + } + }); + const Test = db.model('Test', testSchema); + + const doc = await Test.findOneAndUpdate( + { n: 14521 }, + { age: 7511 }, + { translateAliases: true, upsert: true, returnDocument: 'after' } + ); + + assert.strictEqual(doc.name, '14521'); + assert.strictEqual(doc.age, 7511); + }); + it('schema level translateAliases option (gh-7511)', async function() { const testSchema = new Schema({ name: {