【问题标题】:How do I handle a Unique Field in sails?如何处理风帆中的独特字段?
【发布时间】:2014-05-17 02:22:30
【问题描述】:

我在我的模型中定义了一个唯一字段,但是当我尝试测试时,它似乎没有被sails 检查,因为我得到了Error (E_UNKNOWN) :: Encountered an unexpected error: MongoError: E11000 duplicate key error index: 而不是sails ValidationError。

处理风帆中独特领域的最佳方法是什么?

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

提前谢谢各位。

【问题讨论】:

  • 我们可以得到一些代码吗?
  • @InternalFX 我已更新问题以包含一些代码。谢谢
  • @ginad 请将您的首选解决方案标记为正确答案。

标签: node.js sails.js waterline


【解决方案1】:

unique 属性当前为only creates a unique index in 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 值无用,因为它是在模型声明本身中定义的,因此不能在模型代码中引用。我已经相应地编辑了我的答案,谢谢。

【讨论】:

    【解决方案2】:

    在将电子邮件定义为唯一字段后,您正尝试使用相同的电子邮件地址创建两个用户。

    也许您可以通过该电子邮件地址查询用户 - 如果它已经存在 - 返回错误或更新该用户。

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

    Sails.js 文档中还有一个关于独特模型属性的有趣信息 https://github.com/balderdashy/waterline#indexing

    编辑: 来自http://sailsjs.org/#!documentation/models

    可用的验证有:

    empty, required, notEmpty, undefined, string, alpha, numeric, alphanumeric, email, url, urlish, ip, ipv4, ipv6, creditcard, uuid, uuidv3, uuidv4, int, integer, number, limited, decimal, float , falsey, truthy, null, notNull, boolean, array, date, 十六进制, hexColor, 小写, 大写, after, before, is, regex, not, notRegex, equals, contains, notContains, len, in, notIn, max, min , minLength, maxLength

    【讨论】:

    • 谢谢,是的,我也在考虑使用这种方法,但我只是好奇是否有更好的方法可以生成 ValidationError。
    • 我更新了我的帖子以包含由sailsjs 执行的验证列表。 Unique 不是其中之一 - 因此,在尝试创建包含唯一电子邮件的记录时,由您来解释来自 mongodb 的响应。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      谢谢

      【讨论】:

        【解决方案5】:

        这样做的正确方法!!!

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

        };

        通过这种方式,我们不会破坏验证器的概念!

        【讨论】:

          【解决方案6】:

          在最新版本的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.';
                }
          }
          

          【讨论】:

            猜你喜欢
            • 2016-07-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-09-15
            • 2011-03-11
            • 1970-01-01
            • 1970-01-01
            • 2020-10-08
            相关资源
            最近更新 更多