Skip to content
New issue

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

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

Already on GitHub? # to your account

Manually populated documents get saved as strings instead of ObjectIds in combination with SchemaType getter #14759

Closed
2 tasks done
fardolieri opened this issue Jul 23, 2024 · 0 comments · Fixed by #14760
Closed
2 tasks done
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@fardolieri
Copy link

fardolieri commented Jul 23, 2024

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:

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.

image

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.

@vkarpov15 vkarpov15 added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Jul 23, 2024
@vkarpov15 vkarpov15 added this to the 8.5.2 milestone Jul 23, 2024
vkarpov15 added a commit that referenced this issue Jul 26, 2024
fix(model+document): avoid depopulating manually populated doc as getter value
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants