I’m encountering an error that surprises me, hoping someone can share some context.
Our application uses NestJS (“@nestjs/core”: “^11.1.0”,) and mongoose (“mongoose”: “^8.5.3”).
What I’m trying to accomplish is upserting users from an earlier version of our application (different mongo db) to our current version, I need to preserve the _id field from the legacy document when creating the new one.
This is my query to do so:
const updatedUser = await this.userModel
.findOneAndUpdate(
{
$or: [
{ _id: dto._id },
{ ...(dto.phone ? { phone: dto.phone } : {}) },
{ ...(dto.email ? { email: dto.email } : {}) },
{ ...(dto.orderingCode ? { reuserId: dto.orderingCode } : {}) },
],
},
newUserDocument,
{
upsert: true,
new: true,
},
)
where newUserDocument contains the minimum necessary fields for creating a user based on the ones provided in the dto. However, the dto also includes an _id
field from the V1 DB, so that my new documents retain the same _id
as the legacy documents. It is a requirement that the _id
be the same as the original DB, as our users save a QR of their account info for offline use, and, unfortunately it uses that _id
field as the key.
The email, phone, and orderingCode are values that might be used to de-duplicate users.
The error blocking me from moving forward:
Plan executor error during findAndModify :: caused by :: Performing an update on the path '_id' would modify the immutable field '_id'
I notice that this error arises conditionally based on the fields provided in the dto. If I send an object with email, orderingCode and phone, the upsert proceeds and the returned document has the same _id as the dto.
If the dto does not have any of those fields, the query fails with the above error. For ref, here is an example working dto:
{
"_id":"6749f9ac29adbf976a058303",
"email":"test@gmail.com",
"tag":"webapp",
"phone":"+15555557053",
"orderingCode":"3384",
"customer":"cus_123123",
"hasCard":true,
"fullName":"Full Name"
}
And if I run the same query again I am returned the same document as expected.
If I use this dto (without a phone field), it fails with the provided error:
{
"_id":"6749f9ac29adbf976a058303",
"email":"test@gmail.com",
"tag":"webapp",
"orderingCode":"3384",
"customer":"cus_123123",
"hasCard":true,
"fullName":"Full Name"
}
Any ideas why this would be? To clarify, the intent is to upsert users based on any of their existing _id, email, phone or orderingCode. orderingCode is a marked as unique via mongoose, email is a unique sparse index and phone is unique and sparse. _id is of type mongoose.Schema.Types.ObjectId