Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document.prototype.toObject() with discriminators returns all fields and selectively applies getters #15218

Open
2 tasks done
lcrosetto opened this issue Feb 1, 2025 · 1 comment

Comments

@lcrosetto
Copy link

lcrosetto commented Feb 1, 2025

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.9.7

Node.js version

20.18.0

MongoDB server version

8.0.4

Typescript version (if applicable)

No response

Description

After updating a discriminator key in a document with schema discriminators and getters, the Document includes the fields for the current discriminator, as expected. However, Document.toObject() returns all fields, including those defined in a different discriminator schema, but only applies getters to the fields matching the current discriminator.

Steps to Reproduce

The following script will fail when checking the discriminator fields. In particular, the Document contains only the fields relevant to the discriminator, but the object returned by Document.toObject() contains all fields, including those for the other discriminator schema.

      const conn = mongoose.createConnection(..);

      const baseType = 'baseType';
      const type1Key = 'Type1';
      const type2Key = 'Type2';

      const baseSchema = new mongoose.Schema({
        field: String,
        key: String,
      }, {discriminatorKey: 'key', toObject: {getters: true}});
      const dSchema1 = new mongoose.Schema({
        field1: {
          type: String,
          get(value) {
            return `${value} transformed`;
          },
        },
      });
      const dSchema2 = new mongoose.Schema({
        field2: {
          type: String,
          get(value) {
            return `${value} transformed`;
          },
        },
      });
      baseSchema.discriminator(type1Key, dSchema1);
      baseSchema.discriminator(type2Key, dSchema2);

      const TestModel = conn.model(baseType, baseSchema);

      const field = 'field val';
      const field1 = 'field1 val';
      const field1Transformed = `${field1} transformed`;
      const cdm = new TestModel({
        key: type1Key,
        field,
        field1,
      });
      let cd = await cdm.save();
      assert.equal(cd.field2, undefined);
      assert.equal(cd.field1, field1Transformed);
      cd = cd.toObject();
      assert.equal(cd.field, field);
      assert.equal(cd.key, type1Key);
      assert.equal(cd.field1, field1Transformed);
      assert.equal(cd.field2, undefined);

      const field2 = 'field2 val';
      const field2Transformed = `${field2} transformed`;
      await TestModel.updateOne(
        { _id: cd._id },
        {
          key: type2Key,
          field2,
        },
        {overwriteDiscriminatorKey: true},
      );
      let cd2 = await TestModel.findById(cd._id);
      assert.equal(cd2.field2, field2Transformed);
      assert.equal(cd2.field1, undefined);
      cd2 = cd2.toObject();
      assert.equal(cd2.field, field);
      assert.equal(cd2.key, type2Key);
      assert.equal(cd2.field2, field2Transformed);
      assert.equal(cd2.field1, undefined);

      conn.deleteModel(baseType);

Expected Behavior

As shown in the script above, since a Document with a discriminator includes only the fields relevant to the currently set discriminator key (prior to calling toObject()), I would expect the object returned by toObject() to also only include those fields defined in that discriminator schema.

If all fields must be returned by toObject() (even those not relevant to the current discriminator schema) I would expect all getters to have been called.

@lcrosetto lcrosetto changed the title Document.prototype.toObject() with discriminators returns all fields but selectively applies getters Document.prototype.toObject() with discriminators returns all fields and selectively applies getters Feb 1, 2025
@lcrosetto
Copy link
Author

for (const key of Object.keys(this._doc)) {

I have gotten the above test to pass with the following change:

    const schema = this.$__schema;
    const paths = Object.keys(schema.paths || {});
    for (const key of paths) {

A change may be needed for the deep clone case as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant