Mongoose.js唯一验证

时间:2019-09-23 03:04:24

标签: node.js validation mongoose

注意:问题底部有一个编辑:

我是否可以使用自定义验证器或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.`);
        }
      }
    }
  }

1 个答案:

答案 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");
        }
     });
}