猫鼬条件必填字段验证

Ron*_*537 6 mongoose mongodb node.js mongoose-schema

根据猫鼬内置验证器文档,我可以使用条件必填字段:

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

在此模式中,a仅当 propertyb等于时才需要该属性1

尝试创建新文档按预期工作:

Model.create({ b: 1 }); // throws ValidationError (property a is required)
Run Code Online (Sandbox Code Playgroud)

Model.create({ b: 2 }); // creates document
Run Code Online (Sandbox Code Playgroud)

我的问题是尝试更新现有文档并将属性设置b1因此a应该需要属性。

运行以下代码:

Model.findByIdAndUpdate(model._id, { b: 1 }, { new: true, runValidators: true});
Run Code Online (Sandbox Code Playgroud)

意外更新文档而不会抛出a需要属性的错误。

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

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

我错过了什么吗?有什么方法可以运行整个文档的验证器,而不仅仅是更新的属性,而不必手动获取文档?

Ron*_*537 0

在尝试了中间件和验证器但没有成功之后,我可以通过使用transactions(可从MongoDB 4.0和获得Mongoose 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();
Run Code Online (Sandbox Code Playgroud)

请注意,我没有将 附加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交易文档和MongoDB 文档