Mongoose 的自定义错误消息

Posted

技术标签:

【中文标题】Mongoose 的自定义错误消息【英文标题】:Custom Error Messages with Mongoose 【发布时间】: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

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

【问题讨论】:

【参考方案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);
  
);

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

【讨论】:

您的答案一如既往的准确。如果我可以问你Query 和Model 之间的区别,我看到它们有很多共同点,例如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);但它抛出错误。你知道为什么吗?

以上是关于Mongoose 的自定义错误消息的主要内容,如果未能解决你的问题,请参考以下文章

mongoose 5.7.0 中的自定义验证

Mongoose 验证不记录自定义错误消息

验证 Mongoose Schema 并显示自定义错误消息的最佳实践

处理 Mongoose 验证错误——在哪里以及如何处理?

带有 HTTPStatusCodeResult 和 jQuery 的自定义错误消息

如何在 .Net Core 中返回错误状态代码 401 的自定义错误消息?