I am trying to enforce a Unique Email address when a user signs up. But Mongoose does not seem to be obeying the unique: true flag in my schema.
// NPM Packages
import * as mongoose from 'mongoose';
import * as bcrypt from 'bcrypt';
export const UserSchema = new mongoose.Schema(
{
firstName: {
type: String,
trim: true,
required: [true, 'Please enter First Name'],
},
lastName: {
type: String,
trim: true,
required: [true, 'Please enter Last Name'],
},
email: {
type: String,
match: [
/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
'Please add a valid email address.',
],
required: [true, 'Please enter Email Address'],
unique: true,
lowercase: true,
},
password: {
type: String,
required: [true, 'Please enter a password'],
minlength: [6, 'Password must be at least 6 characters'],
select: false,
},
},
{ timestamps: true },
);
// Encrypt User Password
UserSchema.pre('save', async function(next) {
const salt = await bcrypt.genSalt(10); // Recommended in bcryptjs doc
this.password = await bcrypt.hash(this.password, salt);
});
Use dropDups in your schemas like
email: {
type: String,
match: [
/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
'Please add a valid email address.',
],
required: [true, 'Please enter Email Address'],
unique: true,
lowercase: true,
dropDups: true
}
Related
I have created a schema named userschema.The role object default value is selcted even after specifying a different value from role enum. If I change role manually in the database everything
works fine.
Check the image below.
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true , 'Name is Required'],
unique: true
},
email: {
type: String,
required: [true , "E-mail is Required"],
trim: true,
lowercase: true,
unique: true,
validator:[validator.isEmail , 'Enter a Valid Email']
},
photo: {
type: String,
},
role:{
type:String,
enum: ["user","guide","lead-guide","admin"],
default:"user"
},
password: {
type: String,
trim: true,
minlength:8,
required: [true , 'Enter a Password'],
select:false
},
passwordConfirm: {
type:String,
trim:true,
required: [true , 'Confirm Password'],
validate: {
validator:function(el){
return el === this.password;
},
message: 'Did not match the above password!'
}
},
passwordChangedAt: Date
});
List item
In the post request the role has value of "admin". But after sending the request the role value is "user" which is also the default value in the role object.
I have my MongoDb database named School.
I have "user" collection.
The below is my Schema
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const userSchema = mongoose.Schema(
{
first_name: {
type: String,
required: [true, "first name required"],
trim: true,
text: true,
},
last_name: {
type: String,
required: [true, "last name required"],
trim: true,
text: true,
},
username: {
type: String,
required: [true, "user name required"],
trim: true,
unique: true,
},
email: {
type: String,
required: [true, "email required"],
trim: true,
unique: true,
},
password: {
type: String,
required: [true, "first name required"],
trim: true,
text: true,
}
});
module.exports = mongoose.model('User',userSchema);
In the above schema, email, username are unique.
But even though I pass duplicate values, the insertions are successful.
MY controller.js
const User = require("../models/User");
const bcrypt = require("bcrypt");
const { validateEmail, validateLength } = require("../helpers/validation");
exports.register = async (req, res) => {
try {
const {
first_name,
last_name,
email,
username,
password,
bYear,
bDay,
bMonth,
gender,
} = req.body;
if (!validateEmail(email)) {
return res.status(500).json({
message: "Email is invalid",
});
}
if (!validateLength(first_name, 3, 30)) {
return res.status(500).json({
message:
"First Name - Format Mismatch- Min length - 3 , Max Length - 30",
});
}
const cryptedPassword = await bcrypt.hash(password, 12);
console.log("crypted =" + cryptedPassword);
const user = await new User({
first_name,
last_name,
email,
username,
password : cryptedPassword,
bYear,
bDay,
bMonth,
gender,
}).save();
res.status(200).json(user);
} catch (err) {
console.log(err);
}
};
I have deleted my 'User' collection and again tried to run the 'post' request from Postman. But still, duplicates are getting inserted.
Please suggest me a solution.
Try to set your index by declaring on the schema with the index function:
const mongoose = require('mongoose');
const { ObjectId } = mongoose.Schema;
const userSchema = mongoose.Schema({
first_name: {
type: String,
required: [true, 'first name required'],
trim: true,
text: true,
},
last_name: {
type: String,
required: [true, 'last name required'],
trim: true,
text: true,
},
username: {
type: String,
required: [true, 'user name required'],
trim: true,
unique: false,
},
email: {
type: String,
required: [true, 'email required'],
trim: true,
unique: false,
},
password: {
type: String,
required: [true, 'first name required'],
trim: true,
text: true,
},
});
// Define your index
userSchema.index({ username: 1, email: 1 }, { unique: true });
module.exports = mongoose.model('User', userSchema);
The below is my schema code
const mongoose = require('mongoose');
const { ObjectId } = mongoose.Schema;
const userSchema = mongoose.Schema({
first_name: {
type: String,
required: [true, 'first name required'],
trim: true,
text: true,
},
last_name: {
type: String,
required: [true, 'last name required'],
trim: true,
text: true,
},
username: {
type: String,
required: [true, 'user name required'],
trim: true,
unique: false,
},
email: {
type: String,
required: [true, 'email required'],
trim: true,
unique: false,
},
password: {
type: String,
required: [true, 'first name required'],
trim: true,
text: true,
},
});
// Define your index
userSchema.index({ username: 1, email: 1 }, { unique: true });
module.exports = mongoose.model('User', userSchema);
I came to know, this method of using index for obtaining the unique feature , will cause performance impact..
Reference : https://www.mongodb.com/docs/manual/core/index-creation/#index-build-impact-on-database-performance
I already had my schema like below. It was not working, when tested with duplicates. So I jumped to the above method. But now need a much better solution.
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const userSchema = mongoose.Schema(
{
first_name: {
type: String,
required: [true, "first name required"],
trim: true,
text: true,
},
last_name: {
type: String,
required: [true, "last name required"],
trim: true,
text: true,
},
username: {
type: String,
required: [true, "user name required"],
trim: true,
unique: true,
},
email: {
type: String,
required: [true, "email required"],
trim: true,
unique: true,
},
password: {
type: String,
required: [true, "first name required"],
trim: true,
text: true,
}
});
module.exports = mongoose.model('User',userSchema);
Is there any workaround for this?
I have the following schema for a mongoose model:
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'User must have a name'],
unique: true
},
photo: String,
password: {
type: String,
required: [true, 'User must have a passwod'],
select: false,
minlength: 8
},
passwordConfirm: {
type: String,
required: ['Please confirm the passwod'],
select: false,
validate: {
validator: function(val) {
return this.password === val;
},
message: 'Password and passwordConfirm do not match'
}
}
});
Since password is set as Select:false, it should not be present in the queried object. However, when i create a document as below, it always has the password present:
const user = await userModel.create({
name: req.body.name,
email: req.body.email,
password: req.body.password,
passwordConfirm: req.body.passwordConfirm
});
so i tried prev solutions to this issue
1-dropping collection
2-dropping database
3-adding dropDups
nothing worked
const userSchema = new Schema({
name: {
type: String,
required: [true, "please Enter your Name"],
lowercase: true,
},
username: {
type: String,
required: [true, "please Enter your user name"],
index: { unique: true, dropDups: true },
},
email: {
type: String,
required: [true, "please Enter your Email"],
unique: true,
lowercase: true,
validate: [isEmail, "please Enter a valid Email"],
},
password: {
type: String,
required: [true, "please Enter a Password"],
minlength: [8, "minimum password length is 8 characters"],
},
address: {
type: String,
required: [true, "please Enter your address"],
},
});
module.exports = User = mongoose.model("user", userSchema);
if anyone has an updated solution that would be great
what are you using to add a new user?
I had the same issue i was using User.create(...)
Instead use new User (...) as so
async addUser(req, res) {
const { name, username, email, password, address } = req.body;
try {
const user = new User({
name: name,
username: username,
email: email,
password: password,
address: address,
});
const data = await user.save();
res.status(201).json(data);
} catch (err) {
res.status(400).send(err);
}