私は、バリデータ、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);
バリデータを使用して更新する際の注意点は何ですか? –