背景
我目前正在使用Node.js,Express和MongoDB构建一个网站。我正在使用mongoose来处理我的MongoDB服务器。
现在我在我的Mongoose模式中有一个函数,它检查用户的输入电子邮件地址是否已存在于数据库中。我希望只在创建帐户页面上调用此函数。任何帮助将不胜感激!谢谢!
问题
该功能运行良好但在编辑用户配置文件页面和创建用户页面上调用。这意味着,如果用户未在编辑个人资料页面上更改其电子邮件,则他们无法更新其个人资料。我只希望为创建用户页面调用此验证唯一的电子邮件功能,以便我可以避免此问题。如何根据用户所在的页面运行功能?
代码
我的用户架构中的功能,用于检查电子邮件是否已存在
UserSchema.path('email').validate(function(value, done) {
this.model('User').count({ email: value }, function(err, count) {
if (err) {
return done(err);
}
// If `count` is greater than zero, "invalidate"
done(!count);
});
}, 'Email already exists');
整个用户架构(文件名为user.server.model.js)
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
crypto = require('crypto');
/**
* A Validation function for local strategy properties
*/
var validateLocalStrategyProperty = function(property) {
return ((this.provider !== 'local' && !this.updated) || property.length);
};
/**
* A Validation function for local strategy password
*/
var validateLocalStrategyPassword = function(password) {
return (this.provider !== 'local' || (password && password.length > 6));
};
/**
* User Schema
*/
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
companyName: {
type: String,
trim: true,
default: ''
},
companyWebsite: {
type: String,
trim: true,
default: ''
},
companyAddress1: {
type: String,
trim: true,
default: ''
},
companyAddress2: {
type: String,
trim: true,
default: ''
},
companyCity: {
type: String,
trim: true,
default: ''
},
companyState: {
type: String,
trim: true,
default: ''
},
companyZip: {
type: String,
trim: true,
default: ''
},
phone: {
type: String,
trim: true,
default: ''
},
email: {
type: String,
trim: true,
default: '',
unique: true,
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\@.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: 'testing error message',
required: 'Please fill in a username',
trim: true
},
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For reset password */
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
/**
* Hook a pre save method to hash the password
*/
UserSchema.pre('save', function(next) {
if (this.password && this.password.length > 6) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
next();
});
/**
* Check if email already exists in database
*/
UserSchema.path('email').validate(function(value, done) {
this.model('User').count({ email: value }, function(err, count) {
if (err) {
return done(err);
}
// If `count` is greater than zero, "invalidate"
done(!count);
});
}, 'Email already exists');
/**
* Create instance method for hashing a password
*/
UserSchema.methods.hashPassword = function(password) {
if (this.salt && password) {
return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
} else {
return password;
}
};
/**
* Create instance method for authenticating user
*/
UserSchema.methods.authenticate = function(password) {
return this.password === this.hashPassword(password);
};
/**
* Find possible not used username
*/
UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
var _this = this;
var possibleUsername = username + (suffix || '');
_this.findOne({
username: possibleUsername
}, function(err, user) {
if (!err) {
if (!user) {
callback(possibleUsername);
} else {
return _this.findUniqueUsername(username, (suffix || 0) + 1, callback);
}
} else {
callback(null);
}
});
};
mongoose.model('User', UserSchema);
users.server.routes.js file
'use strict';
/**
* Module dependencies.
*/
var passport = require('passport');
module.exports = function(app) {
// User Routes
var users = require('../../app/controllers/users.server.controller');
// Setting up the users profile api
app.route('/users/me').get(users.me);
app.route('/users').put(users.update);
app.route('/users/accounts').delete(users.removeOAuthProvider);
// Setting up the users password api
app.route('/users/password').post(users.changePassword);
app.route('/auth/forgot').post(users.forgot);
app.route('/auth/reset/:token').get(users.validateResetToken);
app.route('/auth/reset/:token').post(users.reset);
// Setting up the users authentication api
app.route('/auth/signup').post(users.signup);
app.route('/auth/signin').post(users.signin);
app.route('/auth/signout').get(users.signout);
// Finish by binding the user middleware
app.param('userId', users.userByID);
};
答案 0 :(得分:3)
您可以使用Document.isNew
标志仅对创建进行检查。像这样:
UserSchema.pre('save', function(next) {
if (this.isNew) {
// Enforce constraints here
}
if (this.password && this.password.length > 6) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}
next();
});
您也可以使用Document.isModified
,因此在保存挂钩中,您也可以检查this.isModified('email')
。
答案 1 :(得分:1)
比你对Andrew Lavers。我认为他的答案会很好,但我最终做的只是在架构中使用我的电子邮件中的唯一索引验证。
email: {
type: String,
trim: true,
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\@.+\..+/, 'Please fill a valid email address'],
unique: 'testing error message'
},
mean.js样板代码在服务器中有一个名为errors.server.controller.js的控制器,它处理唯一索引验证失败时出现的错误(它们给出错误代码11000和11001)。
exports.getErrorMessage = function(err) {
var message = '';
if (err.code) {
switch (err.code) {
case 11000:
case 11001:
message = getUniqueErrorMessage(err);
break;
default:
message = 'Something went wrong';
}
} else {
for (var errName in err.errors) {
if (err.errors[errName].message) message = err.errors[errName].message;
}
}
return message;
};
当我使用唯一索引验证时,我在编辑个人资料页面上没有任何问题。
我之前尝试过这个独特的属性并且没有用,我发现这是因为如果数据库中已经有重复的值,你必须删除数据库中的所有信息。我听说有其他方法可以解决这个问题,但对我来说删除数据库最简单。
独特的验证指数方法是Mongoose创建者Aaron Heckmann建议的方法,以避免在使用其他方法时遇到的与预期的竞争条件相关的错误。
见http://nraj.tumblr.com/post/38706353543/handling-uniqueness-validation-in-mongo-mongoose