猫鼬条件必填字段验证
Posted
技术标签:
【中文标题】猫鼬条件必填字段验证【英文标题】:mongoose conditional required field validation 【发布时间】:2019-03-15 05:07:59 【问题描述】:根据猫鼬built-in validators documentations,我可以使用条件必填字段:
const schema = mongoose.Schema(
a:
type: String,
required: function ()
return this.b === 1
,
b:
type: Number,
required: true
);
在此架构中,仅当属性 b
等于 1
时才需要属性 a
。
尝试创建新文档按预期工作:
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
)而不是整个文档运行。
我不确定这是预期的行为还是错误...
我错过了什么吗? 有什么方法可以运行整个文档的验证器,而不仅仅是更新的属性,而无需之前手动获取文档?
【问题讨论】:
【参考方案1】:您必须实现通常称为“钩子”的中间件,您可以阅读更多内容 并实现您的需求 https://mongoosejs.com/docs/middleware.html
【讨论】:
这是不正确的,如果我只更新属性b
,则使用钩子我无法访问属性a
,因此如果不获取之前的文档,仍然无法验证该字段。 【参考方案2】:
在尝试了中间件和验证器但没有成功后,我可以通过使用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
【讨论】:
以上是关于猫鼬条件必填字段验证的主要内容,如果未能解决你的问题,请参考以下文章