最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to represent range in mongoose schema? - Stack Overflow

programmeradmin4浏览0评论

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 plicated and doesn't check if the Max range value is bigger than the Min range value, i.e., doesn't check if 10 > 2.

Question:

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

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 plicated and doesn't check if the Max range value is bigger than the Min range value, i.e., doesn't check if 10 > 2.

Question:

  • How would you implement a price range in a schema in mongoose ?
Share edited Mar 28, 2017 at 10:26 Flame_Phoenix asked Mar 28, 2017 at 10:14 Flame_PhoenixFlame_Phoenix 17.6k40 gold badges146 silver badges284 bronze badges 2
  • 1 why don't you change your schema design to range: { minimum: { type: Number, min: 0}, maximum: { type: Number, min: 0}} it would make querying easier. I think – Kxng Kombian Commented Mar 28, 2017 at 10:35
  • I think that also makes sense. However, how would I check that Maximum is > Minimum ? – Flame_Phoenix Commented Mar 28, 2017 at 10:43
Add a ment  | 

1 Answer 1

Reset to default 5

My solution

I decided to have both values in my Schema separately, like in the example bellow:

ine: {
    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.ine.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.ine.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:

ine: {
    currency: { type: String },
    range: {
        min: { 
            type: Number, min: 0,
            validate: {
                validator: function(val){
                    const currMax = this.target.ine.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.ine.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, i.e., the following example will work on an object with MIN = 10:

    ObjModel.update( { _id: "58dd26b5476664e33eec4b93" }, { $set: {"ine.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 paring MIN and MAX, it would be useful to print the value being evaluated as well as the values it is being pared to.

Hope it helps, and inspires!

发布评论

评论列表(0)

  1. 暂无评论