Skip to content

Getter is not applied when schema changes from string to nested schema #15301

Closed
@timheerwagen

Description

@timheerwagen

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.12.1

Node.js version

22.13.9

MongoDB server version

"mongodb-memory-server": "^10.1.4"

Typescript version (if applicable)

^5.8.2

Description

I am trying to migrate a schema from a string to a nested schema object. The getter works, but the new value is not applied to the returned document.

When using toObject with getters, the time string is removed but no new value is applied:

[
  {
    _id: new ObjectId('67c99f04daa6bc446e6bec72'),
    __v: 0,
    id: '67c99f04daa6bc446e6bec72'
  },
  {
    _id: new ObjectId('67c99f05daa6bc446e6bec74'),
    time: { hours: 12, minutes: 35 },
    __v: 0,
    id: '67c99f05daa6bc446e6bec74'
  }
]

When using lean getters with the "mongoose-lean-getters: "^2.2.1" plugin, the time string is not replaced.

[
  {
    _id: new ObjectId('67c99e3dec853f96ef38a72d'),
    time: '12:34',
    __v: 0
  },
  {
    _id: new ObjectId('67c99e3dec853f96ef38a72f'),
    time: { hours: 12, minutes: 35 },
    __v: 0
  }
]

Steps to Reproduce

Reproduction code:

import mongoose, { Schema } from "mongoose";
import mongooseLeanGetters from "mongoose-lean-getters";

import { MongoMemoryServer } from "mongodb-memory-server";

const mongod = await MongoMemoryServer.create();

const uri = mongod.getUri();

await mongoose.connect(uri);

type Time = { hours: number; minutes: number };

const timeStringToObject = (time: string | Time): Time => {
  console.log("runs", time);

  if (typeof time !== "string") return time;

  const [hours, minutes] = time.split(":");

  console.log("time is string", time, {
    hours,
    minutes,
  });

  return { hours: parseInt(hours), minutes: parseInt(minutes) };
};

const oldUserSchema = new Schema<{ time: string }>(
  {
    time: {
      type: String,
      required: true,
    },
  },
  {}
);

const UserModelName = "User";

const OldUser = mongoose.model(UserModelName, oldUserSchema);

await OldUser.create({ time: "12:34" });

mongoose.deleteModel(UserModelName);

const userSchema = new Schema<{ time: Time }>(
  {
    time: {
      type: new Schema(
        {
          hours: { type: Number, required: true },
          minutes: { type: Number, required: true },
        },
        { _id: false }
      ),
      required: true,
      get: timeStringToObject,
    },
  },
  {}
);

userSchema.plugin(mongooseLeanGetters, {
  defaultLeanOptions: { getters: true },
});

const User = mongoose.model(UserModelName, userSchema);

await User.create({ time: { hours: 12, minutes: 35 } });

const usersLean = await User.find().lean({ getters: true });

console.log(
  usersLean,
  (await User.find()).map((doc) => doc.toObject({ getters: true }))
);

await mongod.stop();

process.exit();

Expected Behavior

I expect the string to be replaced by the new object.

Metadata

Metadata

Assignees

No one assigned

    Labels

    helpThis issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions