Как работать с уникальным полем в парусах?

Я определил уникальное поле в своей модели, но когда я попытался проверить, кажется, что оно не проверяется парусами, потому что я получаю 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: '[email protected]'}).then(...).fail(....)
User.create({email: '[email protected]'}).then(...).fail(// throws the mongo error ) 
// and same goes with update it throws error

Заранее спасибо, ребята.


person ginad    schedule 04.04.2014    source источник
comment
мы можем получить код?   -  person InternalFX    schedule 04.04.2014
comment
@InternalFX Я обновил вопрос, включив в него несколько кодов. Спасибо   -  person ginad    schedule 05.04.2014
comment
@ginad Пожалуйста, отметьте предпочтительное решение как правильный ответ.   -  person tvollstaedt    schedule 13.09.2016


Ответы (6)


Атрибут 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 по умолчанию бесполезным, поскольку оно определено в самом объявлении модели и, следовательно, на него нельзя ссылаться в коде модели. Я отредактировал свой ответ соответствующим образом, спасибо.

person tvollstaedt    schedule 13.03.2015

Вы пытаетесь создать двух пользователей с одним и тем же адресом электронной почты после определения адреса электронной почты как уникального поля.

Возможно, вы можете запросить пользователя по этому адресу электронной почты — если он уже существует — вернуть ошибку или обновить этого пользователя.

var params = {email: '[email protected]'};

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, целое, число, конечное, десятичное, float, falsey, truey, null, notNull, boolean, array, date, шестнадцатеричный, hexColor, нижний регистр, верхний регистр, after, before, is, регулярное выражение, not, notRegex, equals, содержит, notContains, len, in, notIn, max, min, minLength, максимальная длина

person Chris McClellan    schedule 05.04.2014
comment
Спасибо, да, я тоже думаю об использовании этого метода, но мне просто любопытно, есть ли лучший способ, который будет генерировать ValidationError. - person ginad; 05.04.2014
comment
Я обновил свой пост, включив в него список проверок, выполненных Sailsjs. Уникальный не является одним из них, поэтому вам остается интерпретировать ответ от mongodb при попытке создать запись, содержащую уникальный адрес электронной почты. - person Chris McClellan; 05.04.2014

Решения @tvollstaedt и Дэвида опубликовали работу, но с этим кодом есть большая проблема. Я боролся с этим весь день, поэтому я публикую этот слегка измененный ответ. Я бы просто прокомментировал, но у меня пока нет очков. Я с удовольствием удалю этот ответ, если они смогут обновить свой, но я бы очень хотел помочь тому, у кого были те же проблемы, что и у меня.

Проблема с приведенным выше кодом с использованием пользовательского валидатора заключается в том, что вы не можете получить доступ к атрибуту "uniqueEmail" из свойств так, как это пытаются сделать оба предыдущих решения. Единственная причина, по которой это работает в этих решениях, заключается в том, что они непреднамеренно выбрасывают «uniqueEmail» в глобальное пространство.

Ниже приведена небольшая модификация кода tvollstaedt, не использующая глобальное пространство. Он определяет uniqueEmail за пределами modual.exports, поэтому он ограничен только модулем, но доступен во всем модуле.

Возможно, еще есть лучшее решение, но это лучшее, что я мог придумать с минимальными изменениями в остальном элегантном решении.

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();
    });
  }
};
person thinktt    schedule 30.06.2015

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

Спасибо

person David Hernandez    schedule 17.05.2015

Правильный способ сделать это!!!

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

};

Таким образом, мы не нарушаем концепцию валидатора!

person Harijs Suters    schedule 14.05.2016

В последней версии паруса v1.2.7 обратные вызовы больше не работают. Если вы столкнетесь с проблемой, когда уникальность не работает на ваших моделях, как я сделал с парусами-монго, вам нужно будет вручную настроить ее в своих контроллерах.

Вот пример

//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.';
      }
}
person Adebola    schedule 23.07.2020