Reputation: 19178
user.schema.js
var Schema = require('mongoose').Schema;
var uniqueValidator = require('mongoose-unique-validator');
var _ = require('lodash');
var userSchema = new Schema({
local: {
username: String, // should exist when local exists
role: String,
hashedPassword: { type: String, select: false }
},
facebook: {
id: String,
token: { type: String, select: false }
},
twitter: {
id: String,
token: { type: String, select: false }
},
google: {
id: String,
token: { type: String, select: false }
}
});
userSchema.path('local').validate(function(local) {
var empty = _.isEmpty(local);
if (empty) {
return true;
}
else if (!empty && local.username) {
return true;
}
else if (!empty && !local.username) {
return false;
}
}, 'Local auth requires a username.');
module.exports = userSchema;
I'm trying to validate that username
is present when local
isn't empty. Ie. when using local authentication, username
should be present.
// should validate
user = {
local: {
username: 'foo';
hashedPassword: 'sfsdfs'
}
};
// shouldn't validate
user = {
local: {
hashedPassword: 'sdfsdfs'
}
};
// should validate (because local isn't being used)
user = {
local: {},
facebook {
...
}
};
I get this error:
/Users/azerner/code/mean-starter/server/api/users/user.schema.js:51
userSchema.path('local').validate(function(local) {
^
TypeError: Cannot read property 'validate' of undefined
It seems that you can't get the path
of objects. I learned here that Schemas have a paths
property. When I console.log(userSchema.paths)
:
{ 'local.username':
{ enumValues: [],
regExp: null,
path: 'local.username',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String] },
_index: null },
'local.role':
{ enumValues: [],
regExp: null,
path: 'local.role',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String] },
_index: null },
'local.hashedPassword':
{ enumValues: [],
regExp: null,
path: 'local.hashedPassword',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String], select: false },
_index: null,
selected: false },
'facebook.id':
{ enumValues: [],
regExp: null,
path: 'facebook.id',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String] },
_index: null },
'facebook.token':
{ enumValues: [],
regExp: null,
path: 'facebook.token',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String], select: false },
_index: null,
selected: false },
'twitter.id':
{ enumValues: [],
regExp: null,
path: 'twitter.id',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String] },
_index: null },
'twitter.token':
{ enumValues: [],
regExp: null,
path: 'twitter.token',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String], select: false },
_index: null,
selected: false },
'google.id':
{ enumValues: [],
regExp: null,
path: 'google.id',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String] },
_index: null },
'google.token':
{ enumValues: [],
regExp: null,
path: 'google.token',
instance: 'String',
validators: [],
setters: [],
getters: [],
options: { type: [Function: String], select: false },
_index: null,
selected: false },
_id:
{ path: '_id',
instance: 'ObjectID',
validators: [],
setters: [ [Function: resetId] ],
getters: [],
options: { type: [Object], auto: true },
_index: null,
defaultValue: [Function: defaultId] } }
So it seems that paths like local.username
and facebook.token
exist, but not "top level" paths like local
and facebook
.
If I try to validate the local.username
path, it doesn't work like I want it to.
userSchema.path('local.username').validate(function(username) {
return !!username
}, 'Local auth requires a username.');
The validation is only applied when local.username
exists. I want to validate that it exists. So when it doesn't exist, the validation isn't applied, and thus it's considered valid and gets saved.
I also tried the following approach, but the outcome is the same as the local.username
approach (validation doesn't get hit when the username isn't present, and it gets labeled as valid).
var Schema = require('mongoose').Schema;
var uniqueValidator = require('mongoose-unique-validator');
var _ = require('lodash');
var userSchema = new Schema({
local: {
username: {
type: String,
validate: [validateUsernameRequired, 'Local auth requires a username.']
},
role: String,
hashedPassword: { type: String, select: false }
},
facebook: {
id: String,
token: { type: String, select: false }
},
twitter: {
id: String,
token: { type: String, select: false }
},
google: {
id: String,
token: { type: String, select: false }
}
});
function validateUsernameRequired(username) {
return !!username;
}
module.exports = userSchema;
Upvotes: 4
Views: 306
Reputation: 2206
Adam, why don't you try a pre-validate hook that conditionally passes an error to the next function. I think this'll give you the flexibility you're looking for. Let me know if it doesn't work.
For example
schema.pre('validate', function(next) {
if(/*your error case */){ next('validation error text') }
else { next() }
})
This will cause mongoose to send a ValidationError
back to whoever tried to save the document.
Upvotes: 1
Reputation: 61
Looks like you are trying to create a custom validation. Not sure if you implemented everything you need for it. It looks like this:
// make sure every value is equal to "something"
function validator (val) {
return val == 'something';
}
new Schema({ name: { type: String, validate: validator }});
// with a custom error message
var custom = [validator, 'Uh oh, {PATH} does not equal "something".']
new Schema({ name: { type: String, validate: custom }});
// adding many validators at a time
var many = [
{ validator: validator, msg: 'uh oh' }
, { validator: anotherValidator, msg: 'failed' }
]
new Schema({ name: { type: String, validate: many }});
// or utilizing SchemaType methods directly:
var schema = new Schema({ name: 'string' });
schema.path('name').validate(validator, 'validation of `{PATH}` failed with
value `{VALUE}`');
here is the link: mongoose custom validation
Upvotes: 0