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

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

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

5 ответов

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

РЕДАКТИРОВАТЬ: взято из http://sailsjs.org/

Доступные проверки:

пустой, обязательный, notEmpty, неопределенный, строка, альфа, числовой, буквенно-цифровой, электронная почта, URL, urlish, ip, ipv4, ipv6, кредитная карта, uuid, uuidv3, uuidv4, int, целое число, число, конечный, десятичный, float, falsey, truey, null, notNull, логическое значение, массив, дата, шестнадцатеричный, hexColor, строчные буквы, прописные буквы, после, до, является, регулярное выражение, не, notRegex, равно, содержит, notContains, len, in, notIn, max, min, minLength, максимальная длина

Решения @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();
    });
  }
};

В последней версии 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.';
      }
}

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

};

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

Другие вопросы по тегам