注意:问题底部有一个编辑:
我是否可以使用自定义验证器或Mongoose.js模型文件中的预钩检查数据库的唯一性。我知道我可以在控制器中检查它,但是我宁愿将它与其余验证器一起放在模型文件中,只是为了保持一致性。
我还知道有一个名为mongoose-unique-validator的npm软件包可以执行此操作,但是我不喜欢安装库来执行一到五行代码顶部的操作。
猫鼬还具有“唯一”属性,如果该项不是唯一的,它将抛出错误。但是他们的文件明确指出这不是验证者。而且它引发的错误不会与验证错误一样被路由。
这是模型文件的相关部分。这将检查数据库,如果没有dup,那么它将创建该文章,但是如果有dup,它将引发错误,但不是我想要的验证错误。如果我仅在存在重复项时返回false,它将忽略验证并创建重复的文章。毫无疑问,这与承诺/异步有关。以下是相关的Mongoose文档https://mongoosejs.com/docs/validation.html#async-custom-validators。他们讨论了唯一属性如何不是验证者https://mongoosejs.com/docs/faq.html。
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const articleSchema = new Schema({
title: {
type: String,
required: [true, "Title is required"],
// unique: true,
// isAsync: true,
validate: {
validator: function(value) {
this.constructor.findOne({title: value}, (err, article) => {
if (err || !article) {
return true;
} else {
// return false;
throw new Error('Duplicate');
}
});
},
message: (props) => `Title "${props.value}" is already in use.`
},
},
content: { type: String, required: true }
});
编辑:我想通了,但是它仅在创建新文章时有效,而不适用于更新。因此,问题仍然悬而未决,但重点是如何使它在更新中起作用。更新时,Mongoose不会像创建时一样将“ this”视为文档对象。相反,“ this”是请求对象,而“ this.constructor.findOne()”抛出错误“ this.constructor.findOne不是函数”。这是修改后的验证器:
title: {
type: String,
required: [true, "Title is required"],
isAsync: true,
validate: {
validator: async function(value) {
const article = await this.constructor.findOne({title: value});
if (article) {
throw new Error(`${value} is already in use.`);
}
}
}
}
答案 0 :(得分:0)
您的validator
函数将仅运行脚本,并且不会将任何回调或诺言传递给猫鼬,因此猫鼬假定验证程序返回true并继续执行该过程。
根据文档,您应该返回Promise或使用回调。
承诺:
validator: function(value) {
var here = this;
return new Promise(function(resolve, reject) {
here.constructor.findOne({title: value}, (err, article) => {
if (err || !article) {
resolve(true);
} else {
resolve(false);
}
});
})
}
回调:(需要设置isAsync: true
)
validator: function(value, cb) {
this.constructor.findOne({title: value}, (err, article) => {
if (err || !article) {
cb(true);
} else {
cb(false, "Content is used");
}
});
}