针对 Mongoose 模式验证对象而不保存为新文档

Posted

技术标签:

【中文标题】针对 Mongoose 模式验证对象而不保存为新文档【英文标题】:Validate object against Mongoose schema without saving as a new document 【发布时间】:2016-05-08 16:20:44 【问题描述】:

我正在尝试验证一些将被插入到新文档中的数据,但不是在许多其他事情需要发生之前。所以我打算在静态方法中添加一个函数,希望能根据模型模式验证数组中的对象。

这是目前为止的代码:

module.exports = Mongoose => 
    const Schema = Mongoose.Schema

    const peopleSchema = new Schema(
        name: 
            type: Schema.Types.String,
            required: true,
            minlength: 3,
            maxlength: 25
        ,
        age: Schema.Types.Number
    )

    /**
     * Validate the settings of an array of people
     *
     * @param   array     people  Array of people (objects)
     * @return  boolean
     */
    peopleSchema.statics.validatePeople = function( people ) 
        return _.every(people, p => 
            /**
             * How can I validate the object `p` against the peopleSchema
             */
        )
    

    return Mongoose.model( 'People', peopleSchema )

所以peopleSchema.statics.validatePeople 是我尝试进行验证的地方。我已通读 mongooses validation 文档,但没有说明如何在不保存数据的情况下验证模型。

这可能吗?

更新

这里的一个答案向我指出了正确的验证方法,这似乎有效,但现在它抛出了Unhandled rejection ValidationError

这是用于验证数据的静态方法(无需插入)

peopleSchema.statics.testValidate = function( person ) 
    return new Promise( ( res, rej ) => 
        const personObj = new this( person )

        // FYI - Wrapping the personObj.validate() in a try/catch does NOT suppress the error
        personObj.validate( err => 
            if ( err ) return rej( err )

            res( 'SUCCESS' )
         )
    )

然后我来测试一下:

People.testValidate(  /* Data */  )
    .then(data => 
        console.log('OK!', data)
    )
    .catch( err => 
        console.error('FAILED:',err)
    )
    .finally(() => Mongoose.connection.close())

使用不遵循架构规则的数据对其进行测试会抛出错误,正如您所看到的,我尝试捕捉它,但它似乎不起作用。

P.S.我使用 Bluebird 来兑现我的承诺

【问题讨论】:

看起来像是***.com/questions/28519480/…的骗子 @Justin 这对你有什么帮助?我正在尝试相同的方法并得到与您在评论中提到的相同的 UnhandledPromiseRejectionWarning 错误。 【参考方案1】:

通过Custom validators 有一种方法可以做到这一点。验证失败时,无法将文档保存到数据库中。

var peopleSchema = new mongoose.Schema(
        name: String,
        age: Number
    );
var People = mongoose.model('People', peopleSchema);

peopleSchema.path('name').validate(function(n) 
    return !!n && n.length >= 3 && n.length < 25;
, 'Invalid Name');

function savePeople() 
    var p = new People(
        name: 'you',
        age: 3
    );

    p.save(function(err)
        if (err) 
             console.log(err);           
         
        else
            console.log('save people successfully.');
    );

或通过validate() 使用与您定义的相同架构来实现此目的的另一种方式。

var p = new People(
    name: 'you',
    age: 3
);

p.validate(function(err) 
    if (err)
        console.log(err);
    else
        console.log('pass validate');
);

【讨论】:

我说“不保存”,所以第一个已经出来了,除非你假设数据无效,我们不知道,(这就是验证的目的..) .第二个看起来可能更合适。我试试看! 所以我可以让验证工作,但不是只返回 false,而是引发错误:Unhandled rejection ValidationError: Person validation failed。我尝试在验证方法上使用 try/catch,但这似乎不起作用。我认为无论如何都有办法在 Mongoose 中处理这个问题 我用更多数据更新了工单。到目前为止,谢谢! @Justin,第一个方法,save() 方法在不保存此记录的情况下捕获if (err) 中的验证错误。我想它可以满足你的要求。如果我错了,请纠正我。 zangw - 应该有没有保存方法,这只是为了验证..根本不保存..我需要验证某些对象是否兼容模型架构(不保存),所以我可以继续做一堆其他查询/保存/更新,一旦这些都成功,我就可以保存这些数据.. 但我需要在执行任何其他先决条件查询/保存之前根据架构验证数据.. 此验证只是其他一些操作的先决条件,不是插入/保存一份文件【参考方案2】:

正如猫鼬文档 https://mongoosejs.com/docs/validation.html 中所述,您可以使用 doc.validate(callback)doc.validateSync() 来检查验证。

不同之处在于您不必像其名称所暗示的那样将await 用于validateSync()。如果验证失败,则返回错误,否则返回undefined。 例如:

const model = new Model(somedata:somedata)

const validatedModel = model.validateSync()
if(!!validatedModel) throw validatedModel

【讨论】:

你是如何使用这个方法的?你在回调函数中放了什么?如果验证失败,是否有通过console.log 打印错误的示例? @AaronFranke 说你有一个const model = new Model(some data) 格式的模型,你可以使用const validator = model.validateSync() 验证创建的模型,如果它是无效的,它将返回一个错误类型,如果它是一个有效的则返回一个未定义模型。所以基本上你可以像这样使用它:if(!!validator) throw validator【参考方案3】:

我编写了以下函数,它根本不需要模型,你只需传递一个对象和 Mongoose 模式,无论它是作为文档还是子文档。子文档也被递归检查:

const validateObjectAgainstMongooseSchema = (checkObject, mongooseSchema, currentPath = "object" = ) => 
    const errors = [];

    for (const key of Object.keys(checkObject)) 
        const checkObjectType = Array.isArray(checkObject[key]) ? "array" : typeof checkObject[key];
        const mongooseType = mongooseSchema.path(key).instance.toLowerCase();
        const valid = mongooseType === checkObjectType;

        if (checkObjectType === "object") 
            errors.push(
                ...validateObjectAgainstMongooseSchema(
                    checkObject: checkObject[key],
                    mongooseSchema: mongooseSchema.path(key).schema,
                    currentPath: `$currentPath.$key`
                )
            );
         else if (!valid) 
            errors.push(`$currentPath.$key should be of type $mongooseType but got $checkObjectType`);
        
    

    return errors;
;

使用以下架构时:


const schema = new mongoose.Schema(
        stringType: 
            type: String
        ,
        numberType: 
            type: Number
        ,
        dateType: 
            type: Date
        ,
        boolType: 
            type: Boolean
        ,
        arrayType: 
            type: Array
        ,
        schemaType: 
            type: new mongoose.Schema(
                embeddedDate: 
                    type: Date
                ,
                embeddedBool: 
                    type: Boolean
                
            )
        
    );

以下产生一个空数组

const errors = schemaUtils.helpers.validateObjectAgainstMongooseSchema(
            checkObject: 
                stringType: "test",
                numberType: 2,
                dateType: new Date("2020-01-01"),
                boolType: true,
                arrayType: ["test", "it"],
                schemaType: embeddedDate: new Date("2020-01-02"), embeddedBool: true
            ,
            mongooseSchema: schema
        );

还有这个

const errors = schemaUtils.helpers.validateObjectAgainstMongooseSchema(
            checkObject: 
                stringType: 1,
                numberType: "1",
                dateType: 1,
                boolType: 1,
                arrayType: 1,
                schemaType: embeddedDate: 1, embeddedBool: 1
            ,
            mongooseSchema: schema
        );

产量:

[
      'object.stringType should be of type string but got number',
      'object.numberType should be of type number but got string',
      'object.dateType should be of type date but got number',
      'object.boolType should be of type boolean but got number',
      'object.arrayType should be of type array but got number',
      'object.schemaType.embeddedDate should be of type date but got number',
      'object.schemaType.embeddedBool should be of type boolean but got number'
    ]

【讨论】:

以上是关于针对 Mongoose 模式验证对象而不保存为新文档的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose - 在保存文档之前为每个对象生成 ObjectID

创建新模式对象后,Mongoose 引用的字段丢失

Mongoose 验证错误:架构配置无效

Mongoose OR 模式验证

使用模式方法在 Mongoose For 循环中保存项目

如何引用我试图保存在 nestjs/mongoose 中的模式?