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 Schema 并显示自定义错误消息的最佳实践