根据猫鼬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
)运行,而不是整个文档。
我不确定这是预期的行为还是错误...
我想念什么吗? 有什么方法可以运行整个文档的验证程序,而不仅是更新后的属性,而不必之前手动获取文档?
答案 0 :(得分:0)
您必须实现通常称为“挂钩”的中间件,您可以阅读更多内容 并实现您的需求 https://mongoosejs.com/docs/middleware.html
答案 1 :(得分: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();
请注意,我没有将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