[英]How do I handle a Unique Field in sails?
我已经在我的模型中定义了一个唯一字段,但是当我尝试测试时,它似乎没有被风帆检查,因为我收到Error (E_UNKNOWN) :: Encountered an unexpected error: MongoError: E11000 duplicate key error index:
而不是帆验证错误。
处理风帆中独特领域的最佳方法是什么?
// model/User.js
module.exports{
attributes: {
email: {required: true, unique: true, type: 'email' },
....
}
// in my controller
User.create({email: 'hello@gmail.com'}).then(...).fail(....)
User.create({email: 'hello@gmail.com'}).then(...).fail(// throws the mongo error )
// and same goes with update it throws error
在此先感谢各位。
unique
属性目前仅在 MongoDB 中创建唯一索引。
您可以使用beforeValidate()
回调来检查具有该属性的现有记录并将结果保存在类变量中。
这种方法可确保您的模型返回正确的验证错误,客户端可以对其进行评估。
var uniqueEmail = false;
module.exports = {
/**
* Custom validation types
*/
types: {
uniqueEmail: function(value) {
return uniqueEmail;
}
},
/**
* Model attributes
*/
attributes: {
email: {
type: 'email',
required: true,
unique: true, // Creates a unique index in MongoDB
uniqueEmail: true // Makes sure there is no existing record with this email in MongoDB
}
},
/**
* Lifecycle Callbacks
*/
beforeValidate: function(values, cb) {
User.findOne({email: values.email}).exec(function (err, record) {
uniqueEmail = !err && !record;
cb();
});
}
}
编辑
正如 thinktt 指出的那样,我以前的解决方案中有一个错误,导致默认的uniqueEmail
值无用,因为它是在模型声明本身中定义的,因此不能在模型代码中引用。 我已经相应地编辑了我的答案,谢谢。
在将电子邮件定义为唯一字段后,您尝试使用相同的电子邮件地址创建两个用户。
也许您可以通过该电子邮件地址查询用户 - 如果它已经存在 - 返回错误或更新该用户。
var params = {email: 'email@email.com'};
User.findOne(params).done(function(error, user) {
// DB error
if (error) {
return res.send(error, 500);
}
// Users exists
if (user && user.length) {
// Return validation error here
return res.send({error: 'User with that email already exists'}, 403.9);
}
// User doesnt exist with that email
User.create(params).done(function(error, user) {
// DB error
if (error) {
return res.send(error, 500);
}
// New user creation was successful
return res.json(user);
});
});
在 Sails.js 文档https://github.com/balderdashy/waterline#indexing 中还有一个关于独特模型属性的有趣内容
编辑:从http://sailsjs.org/#!documentation/models 中提取
可用的验证是:
空、必需、非空、未定义、字符串、字母、数字、字母数字、电子邮件、url、urlish、ip、ipv4、ipv6、信用卡、uuid、uuidv3、uuidv4、int、整数、数字、有限、十进制、浮点数、falsey、真、空、notNull、布尔值、数组、日期、十六进制、hexColor、小写、大写、后、前、是、正则表达式、不、notRegex、等于、包含、notContains、len、in、notIn、max、min、minLength、最长长度
@tvollstaedt 和 David 的解决方案发布了工作,但此代码存在一个大问题。 我一整天都在为此苦苦挣扎,所以我提出了这个稍微修改过的答案。 我只想评论,但我还没有积分。 如果他们可以更新他们的答案,我会很乐意删除这个答案,但我真的很想帮助那些和我遇到同样问题的人。
使用自定义验证器的上述代码的问题在于,您无法像以前的解决方案一样尝试从属性中访问属性“uniqueEmail”。 它在这些解决方案中工作的唯一原因是因为它们无意中将“uniqueEmail”扔进了全局空间。
下面是对tvollstaedt 代码稍作修改,不使用全局空间。 它在 modual.exports 之外定义了 uniqueEmail,因此范围仅限于模块,但可以在整个模块中访问。
可能还有更好的解决方案,但这是我能想出的最好的解决方案,对其他优雅的解决方案进行最小的改动。
var uniqueEmail = false;
module.exports = {
/**
* Custom validation types
*/
types: {
uniqueEmail: function(value) {
return uniqueEmail;
}
},
/**
* Model attributes
*/
attributes: {
email: {
type: 'email',
required: true,
unique: true, // Creates a unique index in MongoDB
uniqueEmail: true // Makes sure there is no existing record with this email in MongoDB
}
},
/**
* Lifecycle Callbacks
*/
beforeValidate: function(values, cb) {
User.findOne({email: values.email}).exec(function (err, record) {
uniqueEmail = !err && !record;
cb();
});
}
};
@tvollstaedt 你的回答很有魅力,顺便说一句,这是迄今为止处理sailsjs“独特性”的最优雅的方式。
谢谢!
这是我使用“sails-validation-messages”添加自定义验证消息的两分钱:
module.exports = { /* Custom validation types */ uniqueEmail: false, types: { uniqueEmail: function(value) { return uniqueEmail; } }, attributes: { firstname:{ type: 'string', required: true, }, lastname:{ type: 'string', required: true, }, email:{ type: 'email', required: true, unique: true, maxLength:50, uniqueEmail:true }, status:{ type: 'string' } }, beforeValidate: function(values, cb) { Application.findOne({email: values.email}).exec(function (err, record) { console.log('before validation ' + !err && !record); uniqueEmail = !err && !record; cb(); }); }, validationMessages: { firstname: { required : 'First name is required', }, lastname: { required : 'Last name is required', }, email: { required : 'Email is required', email : 'Enter valid email', uniqueEmail: 'Email already registered' }, } };
然后在控制器中,您可以像这样处理错误:
module.exports = { create:function(req, res){ var values = req.allParams(); Application.create({ email:values.email, firstname:values.firstname, lastname:values.lastname, _csrf: values.csrf }) exec(function created (err, values) { if(err) { console.log(err); if(err.invalidAttributes) { validator = require('sails-validation-messages'); err.invalidAttributes = validator(Application, err.invalidAttributes); return res.negotiate(err); } } }); } };
谢谢
这样做的正确方法!!!
module.exports = {
schema: true,
migrate: 'safe',
tableName: 'users',
autoCreatedAt: false,
autoUpdatedAt: false,
adapter: 'mysql',
/**
* Custom validation types
*/
types: {
uniquePhone: function(value) {
return value!=='_unique';
}
},
attributes: {
id: {
type: 'integer',
primaryKey: true,
unique: true,
autoIncrement: true
},
email: {
type: 'email'
},
first_name: {
type: 'string'
},
last_name: {
type: 'string'
},
phone: {
type: 'string',
required: true,
uniquePhone: true
}
},
/**
* Lifecycle Callbacks
*/
beforeValidate: function(values, cb) {
Users.findOne({phone: values.phone}).exec(function(err, record) {
// do whatever you want check against various scenarios
// and so on..
if(record){
values.phone='_unique';
}
cb();
});
}
};
通过这种方式,我们不会破坏验证器的概念!
在最新版本的sails v1.2.7 中,回调不再起作用。 如果您遇到唯一性在您的模型上不起作用的问题 - 就像我对sails-mongo 所做的那样,您需要在控制器中手动配置它。
这是一个例子
//SIGNUP
create: async (req, res) => {
const { name, email, password } = req.body;
try {
const userExists = await sails.models.user.findOne({ email });
if (userExists) {
throw 'That email address is already in use.';
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.