Mongoose findByIdAndUpdate未在子文档上运行验证

时间:2015-08-03 18:45:37

标签: node.js mongoose

这是我的模特:

'use strict';
var nested = new Schema({
    name: String
});

var test = new Schema({
    url   : {
        type      : String,
        // First validation
        validate  : [validator.isURL, 'Invalid URL']
    },
    array : [
        {
            type: nested,

            // Second Validation
            validate: [function(value) {console.log("CALLED"); return value.length <=3;}, 'Too long']
        }
    ]
});

module.exports = Parent.discriminator('Test', test);;

以下是我创建新文档的方式:

Test.findOrCreate({url: url}, function(err, model, created) {
    if (created) {
        model.array = whatever;
    }

    model.save(function(err) {
        if (err) {return res.status(422).json(err);}

        next();
    });
});

以下是更新:

Test.findByIdAndUpdate(id, {$set: {array: whatever}}, {new: true, runValidators: true}, function(err, model) {
    if (err) {
        return res.status(422).json(err);
    }

    res.status(200).json(model);
});

假设whatever包含两个案例(新增和更新)长度为4的数组。

创建新模型时,两个验证都按预期工作,但我收到错误。但是,使用findByIdAndUpdate时,只会运行第一个验证,而忽略array属性上的验证(甚至不会调用它)。是什么给了什么?

2 个答案:

答案 0 :(得分:2)

验证器无法在findByIdAndUpdate 上工作(不确定,但在我的情况下没有用),您可以使用中间件来摆脱验证器但是您需要编写一些额外的代码

中间件看起来像这样

[SCHEMA].pre('findOneAndUpdate', function(next){
    // findOneAndUpdate and findByIdAndUpdate, will fire this hook

    console.log(this.getUpdate()); // it will return the update Object
    console.log(this.getQuery());  // it will return the query object
    // Do all validation here and modify the update object
    // this.getUpdate().url = 'stackoverflow.com';

    // for sub-docs you need to use loop;
    if(this.getUpdate() && Array.isArray(this.getUpdate().array))
        this.getUpdate().array = this.getUpdate().array.map(function(val){
            return (val.length <= 3) ? true : 'To Long';
        }); 

    // after all validation call next
    next();
});

答案 1 :(得分:0)

根据documentation,如果update()设置为true,验证器似乎仅适用于findOneAndUpdate()runValidators

你试过了吗?

Test.findOneAndUpdate({_id: id}, {$set: {array: whatever}}, {new: true, runValidators: true}, function(err, model) {
    if (err) {
        return res.status(422).json(err);
    }

    res.status(200).json(model);
});