From f87c8110a1b0e2ada22e74a01e46b6f912e3424d Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 29 Aug 2024 11:41:05 -0400 Subject: [PATCH] fix(document): avoid unnecessary clone() in `applyGetters()` that was triggering additional getters Fix #14840 Fix #14835 Re: #14724 --- lib/document.js | 14 +++++++------- lib/helpers/clone.js | 5 ----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/document.js b/lib/document.js index f6a6016c72e..129d59d7bca 100644 --- a/lib/document.js +++ b/lib/document.js @@ -3856,7 +3856,6 @@ Document.prototype.$toObject = function(options, json) { // Parent options should only bubble down for subdocuments, not populated docs options._parentOptions = this.$isSubdocument ? options : null; - options._skipSingleNestedGetters = false; // remember the root transform function // to save it from being overwritten by sub-transform functions // const originalTransform = options.transform; @@ -3870,13 +3869,13 @@ Document.prototype.$toObject = function(options, json) { ret = clone(this._doc, options) || {}; } - options._skipSingleNestedGetters = true; const getters = options._calledWithOptions.getters ?? options.getters ?? defaultOptions.getters ?? false; + if (getters) { - applyGetters(this, ret, options); + applyGetters(this, ret); if (options.minimize) { ret = minimize(ret) || {}; @@ -4187,12 +4186,11 @@ function applyVirtuals(self, json, options, toObjectOptions) { * * @param {Document} self * @param {Object} json - * @param {Object} [options] * @return {Object} `json` * @api private */ -function applyGetters(self, json, options) { +function applyGetters(self, json) { const schema = self.$__schema; const paths = Object.keys(schema.paths); let i = paths.length; @@ -4228,8 +4226,10 @@ function applyGetters(self, json, options) { if (branch != null && typeof branch !== 'object') { break; } else if (ii === last) { - const val = self.$get(path); - branch[part] = clone(val, options); + branch[part] = schema.paths[path].applyGetters( + branch[part], + self + ); if (Array.isArray(branch[part]) && schema.paths[path].$embeddedSchemaType) { for (let i = 0; i < branch[part].length; ++i) { branch[part][i] = schema.paths[path].$embeddedSchemaType.applyGetters( diff --git a/lib/helpers/clone.js b/lib/helpers/clone.js index b0e37f6cfba..09204b8c8a4 100644 --- a/lib/helpers/clone.js +++ b/lib/helpers/clone.js @@ -40,11 +40,6 @@ function clone(obj, options, isArrayChild) { if (isMongooseObject(obj)) { if (options) { - // Single nested subdocs should apply getters later in `applyGetters()` - // when calling `toObject()`. See gh-7442, gh-8295 - if (options._skipSingleNestedGetters && obj.$isSingleNested) { - options._calledWithOptions = Object.assign({}, options._calledWithOptions || {}, { getters: false }); - } if (options.retainDocuments && obj.$__ != null) { const clonedDoc = obj.$clone(); if (obj.__index != null) {