Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
26.88k stars 3.83k forks source link

Getters not applied in 3-level nested subdoc with `toObject({ getters: true, virtuals: false })` in 8.5 #14840

Closed vkarpov15 closed 1 week ago

vkarpov15 commented 2 weeks ago

Prerequisites

Mongoose version

8.5.x

Node.js version

20.10.0

MongoDB server version

5.0.7

Typescript version (if applicable)

N/A

Description

Consider the following script:

const mongoose = require('mongoose');
require('util').inspect.defaultOptions.depth = 10;

// 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 = mongoose.model('Main', MainSchema);

async function run() {
  await mongoose.connect('mongodb://localhost:27017/test');
  await MainModel.deleteMany({});

  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 });

  console.log('Original Document:', doc);
  console.log('Value', doc.level1.level2.level3.property);
  console.log('With Getters Applied:', objectWithGetters);

  await mongoose.connection.close();
}

run().catch(err => console.log(err));

In 8.4, the output would include property: 'TEST VALUE' uppercased. In 8.5, that no longer happens. See comments on https://github.com/Automattic/mongoose/pull/14728

Steps to Reproduce

See above

Expected Behavior

getters applied

lukas-becker0 commented 2 weeks ago

Hi, thanks for the reproduction, I just tested a bit with the script above 8.5.0 is also working, the issue starts with 8.5.1.

Output mongoose 8.5.0, nodejs 20.17.0, mongodb 7.0.12:

Original Document: {
  level1: {
    level2: {
      level3: {
        property: 'testValue',
        _id: new ObjectId('66cf7f8624943b65e0cdf3c2')
      },
      _id: new ObjectId('66cf7f8624943b65e0cdf3c1')
    },
    _id: new ObjectId('66cf7f8624943b65e0cdf3c0')
  },
  _id: new ObjectId('66cf7f8624943b65e0cdf3bf'),
  __v: 0
}
Value TESTVALUE
With Getters Applied: {
  _id: new ObjectId('66cf7f8624943b65e0cdf3bf'),
  level1: {
    level2: {
      level3: {
        property: 'TESTVALUE',
        _id: new ObjectId('66cf7f8624943b65e0cdf3c2')
      },
      _id: new ObjectId('66cf7f8624943b65e0cdf3c1')
    },
    _id: new ObjectId('66cf7f8624943b65e0cdf3c0')
  },
  __v: 0
}

Output mongoose 8.5.1, nodejs 20.17.0, mongodb 7.0.12:

Original Document: {
  level1: {
    level2: {
      level3: {
        property: 'testValue',
        _id: new ObjectId('66cf80c5ef9ea412985c51c7')
      },
      _id: new ObjectId('66cf80c5ef9ea412985c51c6')
    },
    _id: new ObjectId('66cf80c5ef9ea412985c51c5')
  },
  _id: new ObjectId('66cf80c5ef9ea412985c51c4'),
  __v: 0
}
Value TESTVALUE
With Getters Applied: {
  _id: new ObjectId('66cf80c5ef9ea412985c51c4'),
  level1: {
    level2: {
      level3: {
        property: 'testValue',
        _id: new ObjectId('66cf80c5ef9ea412985c51c7')
      },
      _id: new ObjectId('66cf80c5ef9ea412985c51c6')
    },
    _id: new ObjectId('66cf80c5ef9ea412985c51c5')
  },
  __v: 0
}
vkarpov15 commented 2 weeks ago

We've done some digging and traced this to https://github.com/Automattic/mongoose/pull/14724, specifically the this.$__toObjectShallow() changes. We haven't been able to identify a fix yet, but we're working on it. In the meantime, you should downgrade to <= 8.5.0.

lukas-becker0 commented 2 weeks ago

@vkarpov15 alright thank you :)