How to handle a unique field in sails?

I defined a unique field in my model, but when I tried to test, it seems that it is not checked by sails, because instead of Error (E_UNKNOWN) :: Encountered an unexpected error: MongoError: E11000 duplicate key error index: I get sails ValidationError.

What is the best way to handle a unique field in sails?

 // 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 

Thanks in advance guys.

+6
source share
5 answers

The unique attribute currently creates a unique unique index in MongoDB .

You can use the beforeValidate() to check for an existing record with this attribute and store the result in a class variable.

This approach ensures that your model returns the correct validation error that can be evaluated by customers.

 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(); }); } } 

EDIT

As thinktt noted, an error occurred in my previous solution that made the uniqueEmail default uniqueEmail useless, as it is defined in the model declaration itself and therefore cannot refer to the model code. I edited my answer accordingly, thanks.

+9
source

You are trying to create two users with the same email address after defining the email as a unique field.

Perhaps you can request the user at this email address - if he already exists - return an error or update this user.

 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 and MongoDB: duplicate key error index

There is also an interesting bit about the unique properties of the model in the Sails.js docs https://github.com/balderdashy/waterline#indexing

EDIT: Pulled from http://sailsjs.org/#!documentation/models

Available checks:

empty, required, notEmpty, undefined, string, alpha, numeric, alphanumeric, email, url, urlish, ip, ipv4, ipv6, creditcard, uuid, uuidv3, uuidv4, int, integer, number, final, decimal, float , falsey, truey, null, notNull, boolean, array, date, hexadecimal, hexColor, lowercase, uppercase, after, before, is, regex, not, notRegex, equals, contains, notContains, len, in, notIn, max, min , minLength, maxLength

+5
source

The solutions from @tvollstaedt and David are published, but there is a big problem with this code. I struggled with this all day, so I bring up this slightly modified answer. I would just comment, but I have no points yet. I will be happy to delete this answer if they can update them, but I really would like to help those who had the same problems that I had.

The problem with the above code using a special validator is that you cannot access the uniqueEmail attribute from properties in the same way as previous solutions do. The only reason he works on these solutions is because they inadvertently throw uniqueEmail into the global space.

Below is a small modification of the tvollstaedt code that does not use global space. It defines uniqueEmail outside of modual.exports, so it is bound only to the module, but is accessible throughout the module.

There may be a better solution, but it is the best that I could come up with with a minimal change to an otherwise elegant solution.

 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(); }); } }; 
+2
source

@tvollstaedt Your answer worked like a charm, and by the way, this is the most elegant way to deal with "uniqueness" in sailsjs.

Thanks!

Here are my two cents to add custom validation messages using "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' }, } }; 

Then in the controller you can handle the error as follows:

 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); } } }); } }; 

thanks

0
source

The right way to do it !!!

 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(); }); } 

};

Thus, we do not violate the validator concept!

0
source

All Articles