6

我在模型中定义了一个唯一字段,但是当我尝试测试时,它似乎没有被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

提前谢谢各位。

4

6 回答 6

10

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值无用,因为它是在模型声明本身中定义的,因此无法在模型代码中引用。我已经相应地编辑了我的答案,谢谢。

于 2015-03-13T12:09:17.437 回答
5

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

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

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

可用的验证是:

空,必需,notEmpty,未定义,字符串,字母,数字,字母数字,电子邮件,url,urlish,ip,ipv4,ipv6,信用卡,uuid,uuidv3,uuidv4,int,整数,数字,有限,十进制,浮点数,虚假, truthy,null,notNull,布尔,数组,日期,十六进制,hexColor,小写,大写,之后,之前,是,正则表达式,不,notRegex,等于,包含,notContains,len,in,notIn,max,min,minLength,最长长度

于 2014-04-05T01:22:37.540 回答
2

@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();
    });
  }
};
于 2015-06-30T03:21:51.427 回答
0

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

谢谢

于 2015-05-17T22:36:44.683 回答
0

这样做的正确方法!!!

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

};

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

于 2016-05-14T08:21:37.273 回答
0

在最新版本的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.';
      }
}
于 2020-07-23T12:50:19.577 回答