bcryptjs version: "bcryptjs": "^2.4.3"
mongoose version: "mongoose": "^6.0.12"
I am trying to encrypt user password on user creation or password update. When I create a single user with User.create()
everything works as intended (password is encrypted). When I use User.insertMany()
the data is inserted successfully but the password is not encrypted. This is my schema:
const userSchema = mongoose.Schema(
{
name: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
voterId: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
unique: true,
},
votedFor: [
{
type: mongoose.Schema.ObjectId,
ref: 'Election'
}
],
finishedVoting: {
type: Boolean,
required: true,
default: false
},
isAdmin: {
type: Boolean,
required: true,
default: false,
},
},
{
timestamps: true,
}
)
userSchema.pre('save', async function(next) {
// Only run this function if password was actually modified
if (!this.isModified('password')) return next();
// Hash the password with salt 10
this.password = await bcrypt.hash(this.password, 10);
next();
});
This is some sample data that I am trying to insert:
const voters = [
{
name: "Sherali",
surname: "Samandarov",
voterId: "194199",
password: "FA654644", //will be encrypted
isAdmin: false,
finishedVoting: false
// votedFor: [Object], //
},
{
name: "Sherali",
surname: "Samandarov",
voterId: "184183",
password: "MB454644", //will be encrypted
isAdmin: false,
finishedVoting: false
// votedFor: [Object], //
},
{
name: "Sherali",
surname: "Samandarov",
voterId: "194324",
password: "FA651684", //will be encrypted
isAdmin: false,
finishedVoting: false
// votedFor: [Object], //
}
]
I am guessing that userSchema.pre('save', ...)
does not trigger on insertMany()
for some reason
Solved.
I was able to solve the problem by following @victorkt's answer:
Use
pre('validate')
instead ofpre('save')
to set the value for the required field. Mongoose validates documents before saving, therefore your save middleware won't be called if there are validation errors. Switching the middleware fromsave
tovalidate
will make your function set the password field before it is validated.
So,
userSchema.pre('validate', async function(next) {
// Only run this function if password was actually modified
if (!this.isModified('password')) return next();
// Hash the password with salt 10
this.password = await bcrypt.hash(this.password, 10);
next();
});