猫鼬条件必填字段验证

时间:2018-10-10 10:04:33

标签: node.js mongodb mongoose mongoose-schema

根据猫鼬built-in validators documentations,我可以使用条件必填字段:

const schema = mongoose.Schema({
    a: {
        type: String,
        required: function () {
            return this.b === 1
        }
    },
    b: {
        type: Number,
        required: true
    }
});

在此架构中,仅当属性a等于b时才需要属性1

尝试创建新文档的工作符合预期:

Model.create({ b: 1 }); // throws ValidationError (property a is required)

Model.create({ b: 2 }); // creates document

我的问题是尝试更新现有文档并将属性b设置为1,因此属性a是必需的。

运行以下代码:

Model.findByIdAndUpdate(model._id, { b: 1 }, { new: true, runValidators: true});

意外地更新了文档,而没有引发错误,要求提供属性a

我的猜测是,验证仅针对更新的属性(属性b)运行,而不是整个文档。

我不确定这是预期的行为还是错误...

我想念什么吗? 有什么方法可以运行整个文档的验证程序,而不仅是更新后的属性,而不必之前手动获取文档?

2 个答案:

答案 0 :(得分:0)

您必须实现通常称为“挂钩”的中间件,您可以阅读更多内容 并实现您的需求 https://mongoosejs.com/docs/middleware.html

答案 1 :(得分:0)

使用中间件和验证程序没有任何成功之后,我可以通过使用transactions(从MongoDB 4.0Mongoose 5.2.0获得)来实现此要求

// Create a transaction session
const session = await mongoose.startSession();
session.startTransaction();

// Fetch the model (pass the session)
const model = await Model.findById(modelId).session(session);

// ... update your model here

// Validate the schema
if (model.b === 1 && !model.a) {
    throw new mongoose.ValidationError('property a is required');
}

// Save the changes
await model.save();
await session.commitTransaction();

请注意,我没有将session附加到save函数,因为使用find来获取模型已经附加了它:

  

如果您使用会话从findOne()或find()获取Mongoose文档,则该文档将保留对该会话的引用,并将该会话用于save()。

我发现这种方法的一个问题是MongoDB当前仅在副本集上支持transactions。 可以选择使用run-rs

在没有副本集的情况下在本地运行它的选项
  

要运行本地副本集以在macOS,Linux或Windows上开发,请使用npm全局安装run-rs并运行run-rs --version 4.0.0。 Run-rs将为您下载MongoDB 4.0.0。

有关更多信息,您可以同时检查Mongoose documentations的交易和MongoDB documentations