【问题标题】:Best way to check for mongoose validation error检查猫鼬验证错误的最佳方法
【发布时间】:2013-01-02 15:22:24
【问题描述】:

我的用户模型有两个 validation 函数

User.schema.path('email').validate(function(value, respond) {
  User.findOne({email: value}, function(err, user) {
    if(err) throw err;
    if(user) return respond(false);
    respond(true);
  });
}, 'EMAIL_EXISTS');

username 也一样

User.schema.path('username').validate(function(value, respond) {
  User.findOne({username: value}, function(err, user) {
    if(err) throw err;
    if(user) return respond(false);
    respond(true);
  });
}, 'USERNAME_TAKEN');

它们以下列格式返回错误

{ message: 'Validation failed',
  name: 'ValidationError',
  errors: 
    { username: 
      { message: 'Validator "USERNAME_TAKEN" failed for path username',
        name: 'ValidatorError',
        path: 'username',
        type: 'USERNAME_TAKEN' } } }

email 路径的错误类似。有没有比以下更聪明的方法来检查这些错误?

if (err && err.errors && err.errors.username) { ... }

这有点丑。

【问题讨论】:

    标签: node.js mongoose


    【解决方案1】:

    你为什么不使用validation方法as described in the API

    objectToSave.validate(function(err) {          
      if (err) {
        // handle error
      }     
      else {
        // validation passed
      }
    });
    

    【讨论】:

    • This method is called pre save and if a validation rule is violated, save is aborted and the error is returned to your callback. 这基本上就是我已经在做的事情了。我遇到的问题是处理err 没有太多麻烦。
    【解决方案2】:

    从技术上讲,您必须首先检查错误名称,因为并非所有错误都以相同的方式处理。然后,您必须根据错误名称检查特定属性,如 ValidationError 附带的错误属性。

    另外你将字段名放在错误类型中,这是多余的,最好使用相同的错误类型,因为在错误检查过程中你也会得到字段名。

    所以你的代码可以是这样的:

    User.schema.path('email').validate(function(value, respond) {
      User.findOne({email: value}, function(err, user) {
        if(err) throw err;
        if(user) return respond(false);
        respond(true);
      });
    }, 'exists');
    
    User.schema.path('username').validate(function(value, respond) {
      User.findOne({username: value}, function(err, user) {
        if(err) throw err;
        if(user) return respond(false);
        respond(true);
      });
    }, 'exists');
    

    然后,错误检查程序:

    if (err) {
      switch (err) {
        case err instanceof mongoose.Error.ValidationError:
          for (field in err.errors) {
            switch (err.errors[field].type) {
              case 'exists':
                ...
                break;
              case 'invalid':
                ...
                break;
              ...
            }
          }
          break;
        default:
          ...
      }
    }
    

    如果你想缩短它,你有多种选择。如果您只有一种类型的验证,您可以这样做:

    if (err) {
      if (err instanceof mongoose.Error.ValidationError) {
        for (field in err.errors) {
          ...
        }
      } else {
        // A general error (db, crypto, etc…)
        ...
      }
    }
    

    错误检查过程的最小表达方式与您在帖子中所写的类似:

    if (err) {
      for (field in err.errors) {
        ...
      }
    }
    

    这将起作用,因为如果未定义错误,它将忽略 for。但是您在这里忽略了所有其他错误类型。

    我也认为这些错误布局有点混乱,但不要指望在不久的将来会改变。

    【讨论】:

    • ValidationError 是一般错误,由其他几个具有不同格式和/或属性的模块抛出。最好在错误检查过程中具体并检查err instanceof mongoose.Error.ValidationError
    【解决方案3】:

    只需编写以下代码即可享受。

    if (err) {
        console.log('Error Inserting New Data');
        if (err.name == 'ValidationError') {
            for (field in err.errors) {
                console.log(err.errors[field].message); 
            }
        }
    }
    

    【讨论】:

    • 不是你想要在你的代码中随处可见的东西,但它会成为一个很好的辅助函数。
    【解决方案4】:

    我发现这很有帮助,它可以在数组中显示所有错误。

    例如,我提交了一个密码短且电子邮件无效的表单。

    if (err && err.name === 'ValidationError') {
       err.toString().replace('ValidationError: ', '').split(',')
    }
    

    结果是这样的

    [ 'Please provide a valid email address',
    'The password should be at least 6 characters long' ]
    

    如果您的错误消息中包含逗号 ,,请尝试不使用 .split(',')

    不需要for 循环。确保您的架构中有验证错误消息。对于上面的例子,我有

    const validateEmail = email => {
      const re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
      return re.test(email);
    };
    
    const Schema = mongoose.Schema;
    const userSchema = new Schema({
       ...
       email: {
          type: String,
          trim: true,
          required: 'Email address is required',
          validate: [validateEmail, 'Please provide a valid email address'],
       },
       password: { type: String, set: encryptPassword, maxlength: [6, 'The password should be at least {MAXLENGTH} characters long'] },
       ...
    });
    

    【讨论】:

      【解决方案5】:

      我使用 AngularJS,所以ngRepeat 在 Web 表单上显示我的验证错误。我需要做的就是返回一组错误消息。

      有时 Mongoose 会抛出一个不是验证错误的错误,在这种情况下 err.errors 对象将不存在。我记录执行错误。我仍然使用 Web 表单上的相同位置向用户显示执行错误。

      var makeMongooseErrorMsgArray = function(err){
          var msgArray = [];
          if (err.errors) { // validation errors
              $.each(err.errors, function (key, val) {
                  msgArray.push(val.message);
              });
          } else if (err.message){ // should be execution error without err.errors
              errLogr.log(err); // log execution errors
              msgArray.push(err.message);
          } else {
              msgArray.push('Unknown error');
          }
          return msgArray;
      }
      

      【讨论】:

        【解决方案6】:

        通过阅读所有这些答案,我认为最好创建实用函数并重用它:

        这是处理ValidationError 的函数,通过向客户端发送带有验证消息的所需响应,并可选择使用console.log 在控制台中显示消息。

        function handleValidationError(err, res, consoleLog = false){
          const messages = []
          for (let field in err.errors) {
            messages.push(err.errors[field].message)
            consoleLog && console.log(err.errors[field].message)
          }
          res.status(422).json({ messages })
        }
        

        然后在我们要处理错误的控制器中,我们检查err.name 是否为ValidationError,如果是,我们使用上面的实用函数。

        user.save((err) => {
          if (err) {
            if (err.name === 'ValidationError') return handleValidationError(err, res) // here
            return res.status(500).json({ message: 'Error while creating new user' })
          }
          return res.status(201).json({ message: 'User created' })
        })
        

        然后客户端将收到验证错误作为响应:

        curl\
        -H 'Content-Type: application/json'\
        -d '{"email": "foo", "password": "barbaz"}'\
        http://localhost:3000/user/new
        

        输出:

        {"messages":["Email validation failure"]}
        

        【讨论】:

          【解决方案7】:

          这是我处理猫鼬验证错误的独特方法

          代码仍在进行中,一旦准备好我会更新它,或者您可以贡献扩展我的代码。

          let message = "";
          let title = "Validation Error";
          let code = 400;
          let requiredFields = [];
          for (let field in err.errors) {
              let subMsg = ""
              if (err.errors[field].kind === "required") {
                  requiredFields.push(field)
              }
          }
          if (requiredFields.length > 0) {
              message = "Following fields are required: " + requiredFields.join(", ");
          } else {
              message = "Unknown";
          }
          res.status(code).json({
              status: code,
              message: message,
              title: title
          });
          

          【讨论】:

            【解决方案8】:

            方法#1

            我对这种方法的最佳猜测是使用具有基于承诺的回报的广义验证器, 希望对以后有所帮助

            function validateDoc(model,fieldName) {
              return new Promise((resolve, reject) => {
                model.validate(err => {
                  if (err) {
                    return reject(err.errors[fieldName]);
                  } else {
                    return resolve(model);
                  }
                });
              })
            }
            
            // Access error message in catch() or get the validated doc in then()
            
            validateDoc(model,fieldName)
                       .then((model) => console.log(model))
                       .catch((message) => console.warn(message))
            

            方法 #2

            const userSchema = new Schema({
              name: {
                type:String,
                required:[true,'Name is required.'],
                validate:{
                  validator:(name) => { name.length <= 2 }
                  message:'Name must be longer than two characters'
                }
              }
            })
            const User = mongoose.model('user',userSchema)
            

            使用 validate:Object 内部架构与 validator:functionmessage:String

            稍后当你尝试保存记录时,它会在 catch 函数中显示验证错误对象

            举例

            const newUser = new User({ name: undefined });
            
            newUser.save().catch( ( { errors } ) => { 
            
            let errorBag = [];
            
            Object.keys(errors).forEach((fieldName) => {
            
            errorBag.push({ [fieldName]:errors[fieldName].message })
            
            });
            
             // All the errors with the **fieldName** and  **errorMessages** 
            
            console.log(errorBag);  
            
               })
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-11-21
              • 2020-07-18
              • 2013-11-29
              • 1970-01-01
              • 2021-07-22
              • 2016-09-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多