猫鼬条件必填字段验证

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.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

【讨论】:

以上是关于猫鼬条件必填字段验证的主要内容,如果未能解决你的问题,请参考以下文章

条件JQuery验证必填字段

通过回调或猫鼬模型验证 PassportJS?

如何启用/禁用 HTML5 必填字段验证?

PHP 表单验证 - 必填字段

必填字段的 JSF 验证

向 SharePoint Webpart 添加必填字段验证器