繁体   English   中英

我如何处理风帆中的独特字段?

[英]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 和 MongoDB:重复键错误索引

在 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM