Skip to content

Commit

Permalink
Merge pull request #14844 from Automattic/vkarpov15/gh-14840
Browse files Browse the repository at this point in the history
fix(document): avoid unnecessary clone() in `applyGetters()` that was triggering additional getters
  • Loading branch information
vkarpov15 authored Sep 3, 2024
2 parents 4b1aadc + 6356c5b commit 8f4070a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 12 deletions.
14 changes: 7 additions & 7 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) || {};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
5 changes: 0 additions & 5 deletions lib/helpers/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
30 changes: 30 additions & 0 deletions test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13843,6 +13843,36 @@ describe('document', function() {
assert.strictEqual(requiredCalls[0], doc.config.prop);
assert.strictEqual(requiredCalls[1], doc.config.prop);
});

it('applies toObject() getters to 3 level deep subdocuments (gh-14840) (gh-14835)', async function() {
// Define nested schemas
const Level3Schema = new mongoose.Schema({
property: {
type: String,
get: (value) => value ? value.toUpperCase() : value
}
});

const Level2Schema = new mongoose.Schema({ level3: Level3Schema });
const Level1Schema = new mongoose.Schema({ level2: Level2Schema });
const MainSchema = new mongoose.Schema({ level1: Level1Schema });
const MainModel = db.model('Test', MainSchema);

const doc = await MainModel.create({
level1: {
level2: {
level3: {
property: 'testValue'
}
}
}
});

// Fetch and convert the document to an object with getters applied
const result = await MainModel.findById(doc._id);
const objectWithGetters = result.toObject({ getters: true, virtuals: false });
assert.strictEqual(objectWithGetters.level1.level2.level3.property, 'TESTVALUE');
});
});

describe('Check if instance function that is supplied in schema option is available', function() {
Expand Down

0 comments on commit 8f4070a

Please sign in to comment.