首页 > 解决方案 > 如何为自定义 mongoose SchemaType 的所有实例提供默认验证?

问题描述

我已按照 mongoose 文档创建自定义模式类型。我的实现是功能性的,但没有产生我想要的结果。

我的目标是拥有一个自定义 schemaType,它在转换失败(或转换成功但验证失败时)提供自定义错误消息,而无需在每次在我的 api 模式中使用数据类型时声明验证方法。

这是一个示例(我将尝试在评论中解释):

const mongoose = require('mongoose')

// Create Custom Schema Type
class UUIDv4 extends mongoose.SchemaType {
    constructor(key, options) {
        super(key, options, 'UUIDv4');
    }

    cast(val) {
        if (/*Do UUIDv4 validation check here*/) {

            /* Because of the way mongoose works, this error message is difficult
               to present to a user because the built-in casting error message is 
               always used at the top level.
             */
            throw new Error(`${val} is not a valid version 4 UUID`);
        }
        return val;
    }
}

// Add `UUIDv4` to the type registry
mongoose.Schema.Types.UUIDv4 = UUIDv4;

const entitySchema = new mongoose.Schema({
    entityKey: {
        type: UUIDv4,
        required: true
    }
})

const Entity = mongoose.model('Entity', entitySchema)

const testEntity = new Entity({
    entityKey: "123456789"
})

testEntity.save().then(() => {
    console.log('done')
}).catch((e) => {
    console.log(e.errors.entityKey.reason.message) // This is where the custom message can be found
})

显然,我可以跳过创建自定义 SchemaType,但我希望避免每次在我的模式中使用 entityKey 时都必须指定自定义验证器(它们被大量使用)。

const UUIDv4Validator = {
    validator: function(v) {
        // If is valid. . . return true
        // else return false
    },
    message: 'Invalid UUIDv4'
}

const entitySchema = new mongoose.Schema({
    entityKey: {
        type: String,
        required: true,
        validate: UUIDv4Validator // I don't want to have to do this every time
    }
})

我知道我可以保留自定义模式类型并使用可选的链接运算符在我的 try/catch 语句中检查是否存在此错误,但我宁愿避免这种需要,因为它会重复:

try {
    // do stuff . . .
    await testEntity.save()
} catch (e) {
    const message = e?.errors?.entityKey?.reason?.message ?? e.message. // No thank you!
    // do stuff . . .
}

我尝试阅读文档以了解如何为自定义模式类型创建自定义验证方法,但我未能成功尝试任何工作,到目前为止我还没有在网上找到任何示例。

如何将自定义验证器永久链接到我的 UUIDv4 自定义架构类型,该验证器将评估尝试保存的数据,并在适当时返回我的自定义错误消息?

标签: javascriptnode.jsmongodbmongoosemongoose-schema

解决方案


我通过点击 mongoose SchemaTypes 文档中的链接并挖掘一些 mongoose 插件的源代码找到了答案。

本质上,要制作一个普遍应用于 mongoose SchemaType 的所有实例的自定义验证器,应该将验证器直接传递给 SchemaType 的 validate() 方法。

在自定义的 SchemaType 类定义中,可以通过在类构造函数中调用 super 的验证器方法来完成。这是一个例子:

class UUIDv4 extends mongoose.SchemaType {
    constructor(key, options) {
        super(key, options, 'UUIDv4');
        
        // Call the validate method of super and pass in a validator
        // function and a message to return when validation fails
        this.validate(function(val){
            return isUUIDv4(val) // Example UUIDv4 validation check
        }, '{PATH}: "{VALUE}" is not a valid version 4 UUID')
    }
    
    // Other class methods such as cast(), etc. . .
}

如文档(以及我的原始问题)中所示,猫鼬验证器接受{}包含 avalidator和 a的对象message。尽管它们经常被添加到模式中以提供对特定字段/路径的自定义验证,但可以通过调用SchemaType.validate()(其中 SchemaType 被实际的 SchemaType 名称,即 String 替换)并传入验证器函数,将它们添加到 schemaType 的整体验证中和消息作为两个单独的参数。

对于那些使用自定义 SchemaTypes 的人,例如在我的用例中,可以通过让cast()方法始终返回 true 并仅处理save().


推荐阅读