I have a Mongoose schema that defines a set of possible values a given object can have.
const mongoose = require("mongoose");
const COUNTRIES = ["ES", "PT", "US", "FR", "UK"];
const GENDERS = ["M", "F"];
const surveySchema = {
subject: { type: String, required: true },
country: { type: String, enum: COUNTRIES },
target: {
gender: { type: String, enum: GENDERS }
}
};
module.exports = new mongoose.Schema(surveySchema);;
module.exports.modSchema = surveySchema;
ENUM
I don't personally like ENUM
values because if I add another value to the ENUM
, I have to recompile the entire application again and deploy.
I guess that with an ENUM
such as gender, that will never change, this is not a problem.
However, with countries, my SQL side tells me I should store them because if you have a growing business, you are likely to expand to other countries.
My problem here is that I don't know how to tell Mongoose, at a schema level, that the only allowed values for the countries have to be ["ES", "PT", "US", "FR", "UK"]
.
I guess I could create a collection countries, but then I lack the knowledge on how I would connect them. Would I have to use async validators?
How would you deal with an ENUM
that can change?
Mongoose String and Number types have an enum validator. The enum validator is an array that will check if the value given is an item in the array. If the value is not in the array, Mongoose will throw a ValidationError when you try to save() .
Enumerations, also known as enums, are not supported natively in the Java SDK.
JSON has no enum type. The two ways of modeling an enum would be: An array, as you have currently. The array values are the elements, and the element identifiers would be represented by the array indexes of the values.
Definition. Removes whitespace characters, including null, or the specified characters from the beginning and end of a string. The string to trim.
You can use admin panel to add more country to the country collection. As you are saying that COUNTRIES array can grow, you can use another collection to add more countries on demand from admin panel.
And when you are going to add/save a new record into the survey you can trigger a pre-save hook to mongo for validation.
suppose we have another schema for countries like this.
{
countries: [String]
}
Here is a sample code for the scenario.
const mongoose = require("mongoose");
const GENDERS = ["M", "F"];
const surveySchema = {
subject: { type: String, required: true },
country: { type: String},
target: {
gender: { type: String, enum: GENDERS }
}
};
var Survey = new mongoose.Schema(surveySchema);
Survey.pre('save',function(next){
var me = this;
CountryModel.find({},(err,docs)=>{
(docs.countries.indexOf(me.country) >=0) ? next() : next(new Error('validation failed'));
});
});
This way you can handle dynamic country add without changing the country array and redeploying your whole server.
USING CUSTOM VALIDATOR
const mongoose = require("mongoose");
const GENDERS = ["M", "F"];
const surveySchema = {
subject: {
type: String,
required: true
},
country: {
type: String,
validate: {
isAsync: true,
validator: function(arg, cb) {
CountryModel.find({}, (err, docs) => {
if (err) {
cb(err);
} else {
cb(docs.countries.indexOf(arg) >= 0);
}
}
},
message: '{VALUE} is not a valid country'
}
},
target: {
gender: { type: String, enum: GENDERS }
}
};
you will get an error while saving the survey data in the callback ..
ServeyModel.save((err,doc)=>{
if(err){
console.log(err.errors.country.message);
//Error handle
}else {
//TODO
}
});
Just wanted to add one thing, @Shawon's answer is great. Do know that there are two ways to make a validator async. One is shown above where if you specify the isAsync
flag and then Mongoose will pass that callback into your validator function to be called at the end of your validation, but you should only use that flag if you're not returning a promise. If you return a promise from your custom validator, Mongoose will know it is async and the isAsync
flag is no longer required.
The Mongoose async custom validator doc is found here which shows these both examples really well, great docs. http://mongoosejs.com/docs/validation.html#async-custom-validators
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With