简体   繁体   中英

How to represent range in mongoose schema?

Background

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;
};

Problem:

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, ie, doesn't check if 10 > 2.

Question:

  • How would you implement a price range in a schema in mongoose ?

My solution

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 }
    }
}

Problem

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.

Enter Custom Validators

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!"
}

Final result

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!"
            }
        }
    }
}

Going further

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:

  1. The validator will keep inconsistent objects from being inserted. However, when it does not prevent bad UPDATES, ie, 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.

  1. In the functions to check MIN and MAX, you can print the value being evaluated using {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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM