如何处理帆中的独特场?

时间:2014-04-04 16:41:52

标签: node.js sails.js waterline

我已经在我的模型中定义了一个独特的字段,但是当我尝试测试它时似乎没有被风帆检查,因为我得到Error (E_UNKNOWN) :: Encountered an unexpected error: MongoError: E11000 duplicate key error index:而不是风帆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

先谢谢你们。

6 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分: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: duplicate key error index

在Sails.js文档中还有一些关于唯一模型属性的有趣内容 https://github.com/balderdashy/waterline#indexing

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

拉出来

可用的验证有:

空,必需,notEmpty,undefined,字符串,alpha,数字,字母数字,电子邮件,url,urlish,ip,ipv4,ipv6,creditcard,uuid,uuidv3,uuidv4,int,integer,number,finite,decimal,float ,falsey,truthy,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

答案 2 :(得分:2)

@tvollstaedt和David的解决方案发布了工作,但这段代码存在很大问题。我整天都在苦苦挣扎,所以我提出了这个稍微修改过的答案。我只是评论,但我还没有得分。我很乐意删除这个答案,如果他们可以更新他们的,但我真的想帮助那些遇到同样问题的人。

使用自定义验证程序的上述代码的问题是您无法访问属性" 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();
    });
  }
};

答案 3 :(得分:0)

@tvollstaedt你的反应就像一个魅力,顺便说一下,处理"唯一性"到目前为止在sailsjs。

谢谢!

以下是使用" sails-validation-messages"添加自定义验证消息的两分钱:



st = {sub[0] for sub in y}

x[:] = (sub for sub in x if sub[0] not in st)




然后在控制器中你可以像这样处理错误:



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'
    },
  }
};




由于

答案 4 :(得分: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();
    });
}

};

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

答案 5 :(得分: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.';
      }
}