簡體   English   中英

針對 Mongoose 模式驗證對象而不保存為新文檔

[英]Validate object against Mongoose schema without saving as a new document

我正在嘗試驗證將插入到新文檔中的一些數據,但不是在許多其他事情需要發生之前。 因此,我將向靜態方法添加一個函數,該函數有望根據模型模式驗證數組中的對象。

到目前為止的代碼如下:

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是我嘗試進行驗證的地方。 我已經閱讀了貓鼬驗證文檔,但它沒有說明如何在不保存數據的情況下驗證模型。

這可能嗎?

更新

這里的一個答案向我指出了正確的驗證方法,這似乎有效,但現在它拋出了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())

使用不遵循架構規則的數據對其進行測試會引發錯誤,正如您所看到的,我試圖抓住它,但它似乎不起作用。

PS我用 Bluebird 來兌現我的承諾

有一種方法可以通過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');
});

正如貓鼬文檔https://mongoosejs.com/docs/validation.html中所述,您可以使用doc.validate(callback)doc.validateSync()來檢查驗證。

不同之處在於您不必像其名稱所暗示的那樣對validateSync()使用await 如果驗證失敗,則返回錯誤,否則返回undefined 例如:

const model = new Model({somedata:somedata})

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

我編寫了以下根本不需要模型的函數,您只需傳遞一個對象和 Mongoose 模式,無論它是作為文檔還是子文檔。 子文檔也被遞歸檢查:

const validateObjectAgainstMongooseSchema = ({checkObject, mongooseSchema, currentPath = "object", checkDate} = {}) => {
    if (!checkDate) throw new Error("checkDate has to be provided");

    const errors = [];
    const schemaKeys = Object.keys(mongooseSchema.obj);

    // Check type of provided values
    for (const key of schemaKeys) {
        const checkObjectType = Array.isArray(checkObject[key]) ? "array" : typeof checkObject[key];

        const mongoosePath = mongooseSchema.path(key);

        // If path doesn't exist in schema, jump it
        if (!mongoosePath) continue;

        const mongooseType = mongoosePath.instance.toLowerCase();
        const mongooseRequired = mongoosePath.isRequired;

        let valid = mongooseType === checkObjectType;

        if ((checkObject[key] === undefined || checkObject[key] === null) && !mongooseRequired) {
            // If value undefined and path not required, skip validation
            continue;
        } else if (!checkObject[key] && mongooseRequired) {
            // If value undefined and path required, save error
            errors.push(`${currentPath}.${key} is required but got ${checkObject[key]}`);
            continue;
        } else if ((checkObjectType === "string" || checkObject[key]?.toISOString) && mongooseType === "date") {
            // Check if value is a date disguised as a string
            if (checkDate(checkObject[key])) valid = true;
        } else if (checkObjectType === "object") {
            // If we still have an object, we must have a subschema
            errors.push(
                ...validateObjectAgainstMongooseSchema({
                    checkObject: checkObject[key],
                    mongooseSchema: mongooseSchema.path(key).schema,
                    currentPath: `${currentPath}.${key}`,
                    checkDate: checkDate
                })
            );
            continue;
        }

        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'
    ]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM