'Mongoose findOne and save create new object and trigger uniquevalidator
I'm using mongo 4.4.10 (due to synology limitation) Express, mongoose and UniqueValidator 3.0.0 (the principal suspect)
When doing this
router.get('/test',async (req,res)=>{
try {
const user = await UserModel.findById('abc'); //it find the user with id abc
user.firstname = 'testOk';
await user.save(); // <-- error and server crash
return res.status(200).json({message:'ok'});
} catch (error) {
return res.status(401).json({message:'not ok',error:error});
}
})
The res.status return 401 with message not ok
Error Message:
> properties: {
> message: 'Error, expected `_id` to be unique. Value: `6222469034b2ff0a853f7b78`',
> type: 'unique',
> validator: [Function (anonymous)],
> path: '_id',
> value: ObjectId {
> [Symbol(id)]: Buffer(12) [Uint8Array] [
> 98, 34, 70, 144, 52,
> 178, 255, 10, 133, 63,
> 123, 120
> ]
> }
> },
> kind: 'unique',
> path: '_id',
> value: ObjectId {
> [Symbol(id)]: Buffer(12) [Uint8Array] [
> 98, 34, 70, 144, 52,
> 178, 255, 10, 133, 63,
> 123, 120
> ]
> },
> reason: undefined,
> [Symbol(mongoose:validatorError)]: true
> } }, _message: 'user validation failed' } [nodemon] app crashed - waiting for file changes before starting...
My user schema is as follow :
import mongoose from 'mongoose';
import uniqueValidator from 'mongoose-unique-validator';
import bcrypt from 'bcryptjs';
const Schema = mongoose.Schema;
const UserSchema = new Schema({
email: {
type: String,
trim: true,
lowercase: true,
required: true,
unique: true,
},
firstname:{
type: String,
trim: true,
required: true
},
lastname:{
type: String,
trim: true,
required: true
},
password: {
type: String,
required: true,
select: false
}
}, { timestamps: true });
UserSchema.pre('save', function(next) {
const user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified("password")) return next();
// generate a salt
bcrypt.genSalt((err, salt) => {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
UserSchema.methods.isValidPassword = function(candidatePassword, cb) {
const user = this;
bcrypt.compare(candidatePassword, user.password, (err, isMatch) => {
if (err) return cb(err);
cb(null, isMatch);
});
};
UserSchema.plugin(uniqueValidator);
const UserModel = mongoose.model('user', UserSchema);
export default UserModel;
Why mongoose is trying to create a new object ? Thanks for help
UPDATE
The issue seems to come from the module mongoose-unique-validator 3.0.0, when I comment the UserSchema.plugin(uniqueValidator); it works
Solution 1:[1]
It's because .save() is asynchronous, so you have to wait for it's response. Currently, your code will not wait for the response, and it will return 200 response message before the response from .save() is returned. You should add await:
await user.save();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | NeNaD |
