DouglasGabr / mongoose-lean-defaults

Attach defaults to the results of mongoose queries when using .lean()
https://www.npmjs.com/package/mongoose-lean-defaults
ISC License
15 stars 12 forks source link

[BUG] Wrong default for empty subobject #32

Open ajwootto opened 1 year ago

ajwootto commented 1 year ago

Describe the bug
Seems to be similar to #30

In the latest version (2.2.1) a schema that contains a subdocument (in my case with the _id field turned off) results in an empty object being applied to that field when it is empty in the database.

To Reproduce

const mongoose = require('mongoose')
const mongooseLeanDefaults = require('mongoose-lean-defaults')

const Schema = mongoose.Schema

const ChildSchema = new Schema(
    {
        name: String,
    },
    { _id: false },
)

const ParentSchema = new Schema({
    children: { type: ChildSchema },
})

mongooseLeanDefaults.default(ParentSchema)

const ParentModel = mongoose.model('Parent', ParentSchema)

;(async () => {
    await mongoose.connect(`mongodb://localhost:27017`, {
        dbName: 'userSchema',
    })

    // init one doc
    const doc = new ParentModel()
    await doc.save()

    // once created we fetch it again
    const parent = await ParentModel.findOne({ _id: doc._id })
        .lean({ defaults: true })
        .exec()
    console.log({ parent: parent })

    await mongoose.disconnect()
})()

Output of the log is

{
  parent: {
    _id: new ObjectId("64fb6584e8e22146e4383984"),
    __v: 0,
    children: {}
  }
}

Expected behavior
I would have expected the output to simply not include the "children" field, which was the behaviour in previous versions.

Additional context
Mongoose version: 7.5.0 Node version: 18.16.0

peplin commented 1 year ago

@ajwootto I think I'm experiencing the same issue, but 2.2.1 is the first version of this plugin that I've used, so the expected behavior is unclear to me. What was the last version where this worked for you?

The fix for #30 definitely resolved the case below, where default: undefined is explicitly set in the schema:

const MySchema = new mongoose.Schema(
    {
      sub: {
        type: SubSchema,
        default: undefined
      },
    }
  );

Without default: undefined, we get empty objects with a new generated ObjectID. In your case, you explicitly remove the _id, so simply get an empty object.

The Mongoose docs say that subdocuments default to undefined, and I think it would make sense to match that expectation in this plugin. I think the behavior was changed by the fix for https://github.com/DouglasGabr/mongoose-lean-defaults/issues/18 - by trying to include projected defaults, it results in every undefined subdocument now being an actual object. I am not sure how to match the default Mongoose behavior without breaking the projection support in the lean-defaults plugin.

This is my proposed fix: https://github.com/DouglasGabr/mongoose-lean-defaults/pull/35