Reputation: 25
I am writing an API using Express, MongoDB, and Mongoose. I am somehow able to create multiple users with the same email. However, I shouldn't be able to create another user with the same email address. I have email unique: true
in my user schema, but this isn't working as expected.
Here's my user schema:
var UserSchema = new Schema({
fullName: { type: String, required: [true, 'Full name is required.'] },
emailAddress: {
type: String, required: true, unique: true,
validate: {
validator: function (value) {
// check for correct email format
return /^[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(value)
},
message: `Please enter a valid email address!`
}
},
password: { type: String, required: true }
});
My user authenticate method:
UserSchema.statics.authenticate = function (email, password, callback) {
User.findOne({ emailAddress: email })
.exec(function (err, user) {
if (err) {
return callback(err);
} else if (!user) {
var error = new Error('User not found');
error.status = 401;
return callback(error);
}
bcrypt.compare(password, user.password, function (error, user) {
if (user) {
return callback(null, user);
} else {
return callback();
}
});
});
}
My pre-save hook to hash the password:
UserSchema.pre('save', function (next) {
var user = this;
bcrypt.hash(user.password, 10, function (err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
And finally, my user create route:
router.post('/', function (req, res, next) {
if (req.body.fullName &&
req.body.emailAddress &&
req.body.password &&
req.body.confirmPassword) {
if (req.body.password != req.body.confirmPassword) {
var err = new Error('Passwords do not match!');
err.status = 400;
return next(err);
}
// object with form input
var userData = {
fullName: req.body.fullName,
emailAddress: req.body.emailAddress,
password: req.body.password
};
// schema's 'create' method to insert document into Mongo
User.create(userData, function (error, user) {
if (error) {
var err = new Error('Please enter a valid email.');
err.status = 400;
return next(err);
} else {
// set location header to '/', return no content
res.status(201);
res.location('/');
req.session.userId = user._id;
return res.json(user);
}
});
} else {
var err = new Error('All fields required.');
err.status = 400;
return next(err);
}
});
Upvotes: 0
Views: 1230
Reputation: 46
MongoDB does not create unique index to a field if the field value has duplicates already stored in it.
In your case emailAddress must have duplicates already stored in the database. You can check it by runing the code
mongoose
.model(#modelName)
.collection.createIndex( { "inviteCode": 1 });
After running this code you should be able to see a error message in the console.
Or You can check by running the below code if you have duplicate. The below will fetch documents if have duplicates:
mongoose
.model(#modelName).aggregate([{
"$group": {
"_id": "$loginStatus",
count: { $sum: 1 },
ids: { $push: "$_id" }
}
},{ $match: {
count: { $gt : 1 }
}}])
;
If you emailAddress which are already duplicates you cant create unique: true on it. You would have to run the second query and find out the duplicate email address. You can find the documents with duplicate email in the ids
array.
Upvotes: 1