【问题标题】:Custom Error Messages with MongooseMongoose 的自定义错误消息
【发布时间】:2016-12-21 02:23:29
【问题描述】:

所以根据猫鼬docs,您应该能够在架构中设置自定义错误消息,如下所示:

 var breakfastSchema = new Schema({
  eggs: {
    type: Number,
    min: [6, 'Too few eggs'],
    max: 12
  },
  bacon: {
    type: Number,
    required: [true, 'Why no bacon?']
  }
});

所以我想做类似的事情:

var emailVerificationTokenSchema = mongoose.Schema({
   email: {type: String, required: true, unique: [true, "email must be unique"]},
   token: {type: String, required: true},
   createdAt: {type: Date, required: true, default: Date.now, expires: '4h'}
});

这个想法是,当您尝试保存其中一个令牌时,并且已经存在一个冲突的令牌时,它会弹出一条错误消息,上面写着“电子邮件必须是唯一的”。

但是当我做这样的事情时(我用同一个电子邮件保存一个令牌):

verificationToken.save( function (err) {
    if (err) {
      return console.log(err);
    }
    else {
      return console.log(err);
    }
});

我不断收到这个:

'E11000 duplicate key error: index ___.emailVerificationToken.$email_1 dup key: { : "_____@wdad.com

有什么想法吗?自定义消息不支持唯一参数吗?这是一种可行的处理方式吗?

【问题讨论】:

    标签: node.js mongodb error-handling mongoose


    【解决方案1】:

    由于 unique 不是验证器,因此无法在此方案的架构中出现自定义错误。但是,另一种检查唯一性的方法是使用 exists() 方法。例如:

    const User = require('/path/to/model')
    
    app.post('/route-name', async (req, res) => {
      // destructure the request body 
      const { email, password } = req.body;
      
      // Assuming you have an email property in your user model, we check if the email in the request body exists in the database
      // This can take multiple fields as well.
      const exists = await User.exists({ email: email });
      if (exists) return res.json({ error: 'email exists' });
      
      // rest of your logic if email doesn't exist
    });
    

    【讨论】:

      【解决方案2】:

      更新的 mongoose 版本 5.x.x 支持此特定要求。

      https://mongoosejs.com/docs/middleware.html#error-handling-middleware

      您可以为架构添加 post 方法,并按照以下操作: // 保存用户后,如果用户重复,则返回错误

      userSchema.post('save', function(error: any, doc: any, next: any) {
        if (error.name === 'MongoError' && error.code === 11000) {
          next(new Error('user_exists'));
        } else {
          next();
        }
      });
      

      【讨论】:

        【解决方案3】:

        我是这样处理的:

        schema.post('save', function (error, doc, next) {
            let errorMessage
        
            // map with all unique items you defined in your schema 
            const errorsMap = {
                email: 'your message for existing email',
                otherUniqueItem: 'your message for existing item',
            }
        
            if (error.code === 11000) {
                errorMessage = Object
                    .keys(error.keyValue)
                    .map(key => errorMap[key])
                    .join(', ')
            } else {
                errorMessage = error.message
            }
        
            if (errorMessage) next(new Error(errorMessage))
            else next()
        })
        

        【讨论】:

          【解决方案4】:

          来自 Schema 的唯一值的错误消息确实对人类不友好。 这让我很困扰,但是当我看到错误对象中的剩余键时,我能够设置它。

          在返回错误信息时,

           document.save().then(() => {
                  return res.status(201).json({
                    statusText: "created",
                    message: "document created successfully",
                    data: brand,
                  });
                })
                .catch((error) => {
          
                  // Set custom error for unique keys
                  let errMsg;
                  if (error.code == 11000) {
                    errMsg = Object.keys(error.keyValue)[0] + " already exists.";
                  } else {
                    errMsg = error.message;
                  }
                  res.status(400).json({ statusText: "Bad Request", message: errMsg });
                });
          

          【讨论】:

          • 如果您的 Schema 中有多个唯一键,这将非常有用。
          【解决方案5】:

          您可以添加自定义异步验证器。例如:

           {
                validator: (value) => {
                  return UserModel.findOne({ email: value })
                    .then(user => Promise.resolve(user == null))
                    .catch(error => Promise.reject(false));
                },
                message: "User with this email already exists"
           }
          
          

          【讨论】:

            【解决方案6】:

            感谢大家的解答,我的问题已经解决了。

            我的架构是这样的。

            var User = new Schema({
              username: {type: String, required: [true, "Username is required"], unique: true},
              email: {type: String, required: [true, "Email is required"], unique: true},
              password: {type: String, required: true, unique: false},
            });
            

            我建议使用 like 函数。

            你可以这样使用;

            User.post("save", function (error, doc, next) {
            
              if (error.keyValue.email != null && error.name === "MongoError" && error.code === 11000) {
            
                console.log("Email must be unique");
              } else if (error.keyValue.username != null && error.name === "MongoError" && error.code === 11000) {
                console.log("Username must be unique");
              } else {
                console.log("not found any idea, search for another reasons");
              }
            });
            

            【讨论】:

              【解决方案7】:

              只需应用一个中间件。

              recordingSchema.post('save', function (error, _, next) {
                  next( error.code === 11000 
                    ?   new Error('This item field already exist')
                    :   error)
              });
              

              【讨论】:

                【解决方案8】:

                自定义消息不支持唯一参数吗?

                Mongoose 中的唯一性不是验证参数(如required);它告诉 Mongoose 在 MongoDB 中为该字段创建一个唯一索引。

                唯一性约束完全在 MongoDB 服务器中处理。当您添加具有重复键的文档时,MongoDB 服务器将返回您所显示的错误 (E11000...)。

                如果您想创建自定义错误消息,您必须自己处理这些错误。 Mongoose documentation“错误处理中间件”)为您提供了如何创建自定义错误处理的示例:

                emailVerificationTokenSchema.post('save', function(error, doc, next) {
                  if (error.name === 'MongoError' && error.code === 11000) {
                    next(new Error('email must be unique'));
                  } else {
                    next(error);
                  }
                });
                

                (虽然这并没有为您提供唯一性约束失败的特定字段)

                【讨论】:

                • 您的答案一如既往的准确。如果我可以问你QueryModel 之间的区别,我看到它们有很多共同点,例如Model.deleteMany()Query.prototype.deleteMany()
                • @Alexander 我很确定Model.deleteMany 创建(并返回)一个Query 实例,在该实例上调用Query.prototype.deleteMany。该查询实例表示“删除多个”操作。
                【解决方案9】:

                您可以在源代码中重写错误消息,因此在节点模块中。这是一个路径: YOUR_PROJECT/node_modules/mongoose/lib/error/validation.js

                那么你对任何额外的包都没有问题。

                【讨论】:

                • node_modules 不得修改,如果由于某种原因安装更新,您将丢失修改
                【解决方案10】:

                Mongoose 5.x.x 的更新版本

                MySchema.post('save', function (error, doc, next) {
                    if (err.name === 'BulkWriteError' && error.code === 11000) 
                        next(new Error('This item already exists, please try again'));
                    else next(error);
                });
                

                【讨论】:

                • 你是对的,但条件的第一部分是不必要的。 ` if (error.code === 11000) ` 就够了...
                【解决方案11】:
                verificationToken.save( function (err) {
                    if (err) {
                      return res.status(400).send({
                          message: (err.name === 'MongoError' && err.code === 11000) ? 'Email already exists !' : errorHandler.getErrorMessage(err)
                      });
                    }
                    else {
                      return console.log('No Error');
                    }
                  });
                

                【讨论】:

                  【解决方案12】:

                  在您尝试时无法直接实现,但您可能想查看mongoose-unique-validator,如果违反唯一性,它允许自定义错误消息。

                  您应该特别感兴趣关于custom errors 的部分。

                  得到你想要的

                  “电子邮件必须是唯一的”

                  看起来和这个类似

                  var uniqueValidator = require('mongoose-unique-validator');
                  ...
                  emailVerificationTokenSchema.plugin(uniqueValidator, { message: '{PATH} must be unique' });
                  

                  【讨论】:

                  • 这个插件正是我要找的!
                  • 我关注了您的链接,并且正在尝试使用自定义错误消息。我不想只更改消息部分(如您的示例),而是更改整个响应。所以我正在运行: uniqueValidator.defaults.message = '错误,预期 {PATH} 是唯一的。'然后:userSchema.plugin(uniqueValidator);但它抛出错误。你知道为什么吗?
                  猜你喜欢
                  • 2021-06-03
                  • 2021-08-11
                  • 2018-04-17
                  • 2016-09-03
                  • 1970-01-01
                  • 2015-09-21
                  • 2011-04-27
                  • 2018-09-02
                  • 2021-09-13
                  相关资源
                  最近更新 更多