Skip to content
New issue

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

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

Already on GitHub? Sign in 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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