Reputation: 17574
Lets say I am doing a schema about fruits that you can buy. In this schema, a fruit has a price range:
let fruit = {
name: "banana",
price: {
currency: "EUR",
range: [2, 10]
}
};
To achieve saving the above object, I am trying to use the following schema:
let fruitSchema = {
name: {type: String, required: true},
price: {
currency: {type: String, required: true},
range: [{
type: Number,
min: 0
}],
validate: [arraySize]
}
};
const arraySize = function arrayLimit(val) {
return val.length === 2;
};
My solution to the range part feels clunky, over complicated and doesn't check if the Max range value is bigger than the Min range value, i.e., doesn't check if 10 > 2.
Upvotes: 3
Views: 6550
Reputation: 17574
I decided to have both values in my Schema separately, like in the example bellow:
income: {
currency: { type: String },
range: {
min: { type: Number, min: 0 },
max: { type: Number, min: 0 }
}
}
However, now I am left with a problem. How to check that my MAX >= MIN
at all times, and that MIN <= MAX
??
Given that nor MIN nor MAX are mandatory, one can have an object with just an upper range, or just a lower one.
To fix this validation issue, I used custom validator functions. Validators were the missing piece in the puzzle, and allowed me to enforce max and min restrictions:
validate object for min:
validate: {
validator: function(val){
const currMax = this.target.income.range.max;
return (currMax !== undefined ? val <= currMax : true);
},
message: "The MIN range with value {VALUE} must be <= than the max range!"
}
validate object for max:
validate: {
validator: function(val) {
const currMin = this.target.income.range.min;
return (currMin !== undefined ? val >= currMin : true);
},
message: "The MAX range with value {VALUE} must be >= than the min range!"
}
Thus, the final result is as follows:
income: {
currency: { type: String },
range: {
min: {
type: Number, min: 0,
validate: {
validator: function(val){
const currMax = this.target.income.range.max;
return (currMax !== undefined ? val <= currMax : true);
},
message: "The MIN range with value {VALUE} must be <= than the max range!"
}
},
max: {
type: Number, min: 0,
validate: {
validator: function(val) {
const currMin = this.target.income.range.min;
return (currMin !== undefined ? val >= currMin : true);
},
message: "The MAX range with value {VALUE} must be >= than the min range!"
}
}
}
}
This solution is nice, shows advanced knowledge and does the requirements. In you try to insert an object where MIN > MAX
, you will have a nice error message with the VALUE
being inserted.
However, I have the following questions / suggestions for improvement, that I didn't add because I don't yet know how to do:
The validator will keep inconsistent objects from being inserted. However, when it does not prevent bad UPDATES, i.e., the following example will work on an object with MIN = 10:
ObjModel.update(
{ _id: "58dd26b5476664e33eec4b93" },
{ $set: {"income.range.max": 1}} );
To do updates on objects using validators, you must use the save
method, and follow the convention described at the end of the mongoose docs.
Model.findOne({ name: 'borne' }, function (err, doc){
doc.name = 'jason borne';
doc.visits.$inc();
doc.save();
});
Which will trigger the validator as expected.
{VALUE}
. However, can you use other values of the object? When comparing MIN and MAX, it would be useful to print the value being evaluated as well as the values it is being compared to. Hope it helps, and inspires!
Upvotes: 5