2016-05-25 39 views
1

私は、バリデータ、PhotosSchema、UserSchemaを含む2つのスキーマを持っています。 mongooseの 'update'関数は、(わかっている限り)ネイティブmongoドライバを使用しているため、トリガーと検証のチェックは行われません。 したがって、両方のスキーマに私はこれを行う:写真スキーマでマングース検証ツール

PhotosSchema.pre('update', function(next) { 
    this.options.runValidators = true; 
    next(); 
}) 

、それは素晴らしい作品!各更新の前に検証を実行します。 しかし、何らかの理由でバリデータをトリガーすることはありませんが、前回の更新時に 'これ'を調べるとすべてのバリデータが表示されますが、機能を呼び出す理由が何であるかはわかりません。

ファイルここに添付:) 写真スキーマ:

'use strict'; 

var mongoose = require('mongoose'), 
    crate = require('mongoose-crate'), 
    S3 = require('mongoose-crate-s3'); 
var path = require('path'); 
var consts = require('../../config/environment/shared') 


var PhotosSchema = new mongoose.Schema({ 
    userId :{ 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'User', 
    required: true 
    }, 
    photoIndex: { 
    type: Number, 
    validate: [photosLimit, '{PATH} exceeds the limit of ' + consts.MAX_PHOTOS] 
    } 
}, {timestamps: true}); 

function photosLimit(val){ 
    return val < consts.MAX_PHOTOS; 
} 

PhotosSchema.createFilePathAtAws = function(attachment) { // where the file is stored in the bucket - defaults to this function 
    return '/'+ attachment.userId+ '/' + attachment.photoIndex; 
} 

PhotosSchema.plugin(crate, { 
    storage: new S3({ 
    key: process.env.AMAZON_KEY, 
    secret: process.env.AMAZON_SECRET, 
    bucket: process.env.AMAZON_BUCKET, 
    acl: 'public-read-write', // defaults to public-read 
    region: 'us-standard', // defaults to us-standard 
    path: PhotosSchema.createFilePathAtAws 
    }), 
    fields: { 
    file: {} 
    } 
}); 

/** 
* Update in mongoose bypass the validators and is using the mongo driver for updating. 
* therefor for each update we will set the flag of run validators to true before updating. 
*/ 
PhotosSchema.pre('update', function(next) { 
    this.options.runValidators = true; 
    next(); 
}) 

export default mongoose.model('Photos', PhotosSchema); 

ユーザースキーマ:

'use strict'; 

import crypto from 'crypto'; 
import mongoose from 'mongoose'; 
import Photos from '../photos/photos.model' 
var PhotosSchema = Photos.schema; 
mongoose.Promise = require('bluebird'); 
import {Schema} from 'mongoose'; 
var consts = require('../../config/environment/shared'); 

const AUTH_TYPES = consts.AUTH_TYPES; 

var UserSchema = new Schema({ 
    name: { 
    type: String, 
    required: true 
    }, 

    email: { 
    type: String, 
    lowercase: true, 
    required: true, 
    }, 

    sex: { 
    type: String, 
    lowercase: true, 
    enum: ['male', 'female'], 
    required: true, 
    validate: [friendsLimit, '{PATH} exceeds the limit of ' + consts.MAX_FRIENDS] 
    }, 

    preferredSex: { 
    type: String, 
    lowercase: true, 
    enum: ['male', 'female'], 
    required: true 
    }, 

    role: { 
    type: String, 
    default: 'user', 
    required: true 
    }, 

    about: String, 

    preferredAge: { 
    minAge: { 
     type: Number, 
     required: true 
    }, 
    maxAge: { 
     type: Number, 
     required: true 
    }, 
    validate: [ageRangeValidate, '{PATH} Age range must be: ' + consts.MIN_AGE + '-' + consts.MAX_AGE] 
    }, 

    team: { 
    type: [{ 
     type: Schema.Types.ObjectId, 
     ref: 'Users', 
     required: true 
    }], 
    validate: [friendsLimit, '{PATH} exceeds the limit of ' + consts.MAX_FRIENDS] 
    }, 

    usedUsers: { 
    type: Object, 
    default: {} 
    }, 

    matches: { 
    type: Object, 
    default: {} 
    }, 

    photos: { 
    type: [PhotosSchema], 
    validate: [photosLimit, '{PATH} exceeds the limit of 5'] 
    }, 

    birthdate: { 
    type: 'Date', 
    required: true 
    }, 

    profilepic: String, 

    password: { 
    type: String, 
    }, 

    provider: { 
    type: String, 
    required: true 
    }, 

    salt: String, 

    facebook: {}, 

    google: {}, 

    github: {} 
}, {timestamps: true}); 


// validators 
function ageRangeValidate(val) { 
    // TODO 
    return true; 
} 
function friendsLimit(val) { 
    console.log("USER MODEL VALIDATE "); 
    return val.length <= consts.MAX_FRIENDS; 
} 
function photosLimit(val) { 
    console.log("USER MODEL VALIDATE - m in user.model, at PhotosLimit function, this user has " + val.length + "Photos"); 
    return val.length < consts.MAX_PHOTOS; 
} 

/** 
* Virtuals 
*/ 

// Public profile information 
UserSchema 
    .virtual('profile') 
    .get(function() { 
    return { 
     'name': this.name, 
     'role': this.role 
    }; 
    }); 

// Non-sensitive info we'll be putting in the token 
UserSchema 
    .virtual('token') 
    .get(function() { 
    return { 
     '_id': this._id, 
     'role': this.role 
    }; 
    }); 


/** 
* Validations 
*/ 

// Validate empty email 
UserSchema 
    .path('email') 
    .validate(function (email) { 
    console.warn("USER MODEL VALIDATE "); 
    if (AUTH_TYPES.indexOf(this.provider) !== -1) { 
     return true; 
    } 
    return email.length; 
    }, 'Email cannot be blank'); 

// Validate empty password 
UserSchema 
    .path('password') 
    .validate(function (password) { 
    console.warn("USER MODEL VALIDATE "); 
    if (AUTH_TYPES.indexOf(this.provider) !== -1) { 
     return true; 
    } 
    return password.length; 
    }, 'Password cannot be blank'); 

// Validate email is not taken 
UserSchema 
    .path('email') 
    .validate(function (value, respond) { 
    console.warn("USER MODEL VALIDATE "); 
    var self = this; 
    return this.constructor.findOne({email: value}).exec() 
     .then(function (user) { 
     if (user) { 
      if (self.id === user.id) { 
      return respond(true); 
      } 
      return respond(false); 
     } 
     return respond(true); 
     }) 
     .catch(function (err) { 
     throw err; 
     }); 
    }, 'The specified email address is already in use.'); 

var validatePresenceOf = function (value) { 
    return value && value.length; 
}; 

/** 
* Pre-save hook 
*/ 
UserSchema 
    .pre('save', function (next) { 
    // Handle new/update passwords 
    if (!this.isModified('password')) { 
     return next(); 
    } 

    if (!validatePresenceOf(this.password) && AUTH_TYPES.indexOf(this.provider) === -1) { 
     return next(new Error('Invalid password')); 
    } 

    // Make salt with a callback 
    this.makeSalt((saltErr, salt) => { 
     if (saltErr) { 
     return next(saltErr); 
     } 
     this.salt = salt; 
     this.encryptPassword(this.password, (encryptErr, hashedPassword) => { 
     if (encryptErr) { 
      return next(encryptErr); 
     } 
     this.password = hashedPassword; 
     next(); 
     }); 
    }); 
    }); 

/** 
* Methods 
*/ 
UserSchema.methods = { 
    /** 
    * Authenticate - check if the passwords are the same 
    * 
    * @param {String} password 
    * @param {Function} callback 
    * @return {Boolean} 
    * @api public 
    */ 
    authenticate(password, callback) { 
    if (!callback) { 
     return this.password === this.encryptPassword(password); 
    } 

    this.encryptPassword(password, (err, pwdGen) => { 
     if (err) { 
     return callback(err); 
     } 

     if (this.password === pwdGen) { 
     callback(null, true); 
     } else { 
     callback(null, false); 
     } 
    }); 
    }, 

    /** 
    * Make salt 
    * 
    * @param {Number} byteSize Optional salt byte size, default to 16 
    * @param {Function} callback 
    * @return {String} 
    * @api public 
    */ 
    makeSalt(byteSize, callback) { 
    var defaultByteSize = 16; 

    if (typeof arguments[0] === 'function') { 
     callback = arguments[0]; 
     byteSize = defaultByteSize; 
    } else if (typeof arguments[1] === 'function') { 
     callback = arguments[1]; 
    } 

    if (!byteSize) { 
     byteSize = defaultByteSize; 
    } 

    if (!callback) { 
     return crypto.randomBytes(byteSize).toString('base64'); 
    } 

    return crypto.randomBytes(byteSize, (err, salt) => { 
     if (err) { 
     callback(err); 
     } else { 
     callback(null, salt.toString('base64')); 
     } 
    }); 
    }, 

    /** 
    * Encrypt password 
    * 
    * @param {String} password 
    * @param {Function} callback 
    * @return {String} 
    * @api public 
    */ 
    encryptPassword(password, callback) { 
    if (!password || !this.salt) { 
     return null; 
    } 

    var defaultIterations = 10000; 
    var defaultKeyLength = 64; 
    var salt = new Buffer(this.salt, 'base64'); 

    if (!callback) { 
     return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength) 
     .toString('base64'); 
    } 

    return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, (err, key) => { 
     if (err) { 
     callback(err); 
     } else { 
     callback(null, key.toString('base64')); 
     } 
    }); 
    } 
}; 


/** 
* Update in mongoose bypass the validators and is using the mongo driver for updating. 
* therefor for each update we will set the flag of run validators to true before updating. 
*/ 
UserSchema.pre('update', function(next) { 

    this.options.runValidators = true; 
    next(); 
}) 
export default mongoose.model('User', UserSchema); 

答えて

1

Mongoose Validation docsによると、あなたのデータを更新するときにバリデータを実行することができますが、明示的にマングースを伝える必要がありますそれらを実行します。

マングースも更新()とfindOneAndUpdate() 動作の検証をサポートしてい

これは、上記のリンクから取ら更新バリセクションからの引用です。 Mongoose 4.xでは、デフォルトで更新バリデータがオフになっています - runValidatorsオプションを指定する必要があります。

更新バリデーターを有効にするには、 update()またはfindOneAndUpdate()のrunValidatorsオプションを設定します。注意してください:いくつかの警告があるので、更新バリデータはデフォルトで になっています。

+0

バリデータを使用して更新する際の注意点は何ですか? –

関連する問題