Skip to content

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

Closed
@lcrosetto

Description

@lcrosetto

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    new featureThis change adds new functionality, like a new method or class

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions