Manually populated documents get saved as strings instead of ObjectId
s in combination with SchemaType getter #14759
Closed
Description
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.5.1
Node.js version
20.15.1
MongoDB server version
7.0.12
Typescript version (if applicable)
No response
Description
I use a SchemaType getter on ObjectId
because I think strings are more convenient to work with than ObjectIds.
Their use is described and mentioned here:
- https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.get()
- https://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration.html#schematype-getters
- I want to auto convert ObjectId to string #6996 (comment)
Have a look at the code snippet below. I cannot query for a pet anymore, given its owner.
I think that is because pet.save()
unexpectedly saved the owner id as a string into the mongoDB instead of an ObjectId
.
Steps to Reproduce
/**
* I want to globally work with strings instead of ObjectIds
* because that allows me to reuse my underlying types
* across server and client.
*
* Also see:
* https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.get()
* https://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration.html#schematype-getters
* https://github.com/Automattic/mongoose/issues/6996#issuecomment-434063799
*/
mongoose.Schema.ObjectId.get(
value => {
if (value?.constructor?.name?.toLowerCase() === 'objectid') return String(value)
return value
}
)
const ownerSchema = new mongoose.Schema({ name: 'String' })
const petSchema = new mongoose.Schema({
name: 'String',
owner: { type: 'ObjectId', ref: 'owner' }
})
const Owner = mongoose.model('owner', ownerSchema)
const Pet = mongoose.model('pet', petSchema)
const owner = new Owner({ name: 'Alice' })
const pet = new Pet({ name: 'Kitty', owner: owner })
await owner.save()
// pet.owner = pet.owner._id // Manually depopulating it like this makes the whole thing work
await pet.save()
/**
* The property 'owner' of 'pet' has unexpectedly been saved
* as a string into the mongoDB instead of ObjectId.
*
* No matter how I query for it, mongoose is not
* able to find it...
*/
const reloadAttempts = await Promise.all([
Pet.findOne({ owner: owner }),
Pet.findOne({ owner: owner._id }),
Pet.findOne({ owner: String(owner._id) }),
Pet.findOne({ owner: new mongoose.Types.ObjectId(owner._id) }),
])
console.log(reloadAttempts) // Logs [ null, null, null, null ] but shouldn't
Expected Behavior
I expect my reloadAttempts
to not be all null
.
Also the ObjectId getter should not change the mongoDB data structure.
Activity