How to validate object keys and values in Mongoose Schema?

纵饮孤独 提交于 2021-01-28 07:30:47

问题


In my Mongoose Schema I'm trying to simulate a dictionary offersInCategory that looks like this:

offersInCategory = { "Electronics": 2, "Furniture": 5 };

Mongoose doesn't support dictionaries so I'm forced to use object literals in an array instead, like so:

offersInCategory: [{
  category: {
    type: String, 
    enum: ['Furniture', 'Household', 'Electronicts', 'Other']
  },
  val: {
    type: Number, 
    min: 0
  }
}]

My problem with this approach is it feels unintuitive. Furthermore it doesn't prevent my model from creating multiple entries for the same category, as so:

offersInCategory = [ { category: "Furniture", val: 2 }, { category: "Furniture", val: 0} ]

Ideally I'd have my offersInCategory property be structured like this:

offersInCategory : {
  "Furniture" : 0, 
  "Electronics" : 4 
}

But I don't know how to restrict it so that only certain keys can be assigned to the offersInCategory object (kind of like an enum for keys, not values) with no duplicates. I also don't know how to ensure the values for my restricted keys are numbers in a specific range. How can this be accomplished?


回答1:


Option 1 (with "dictionaries"): You can use the Object constructor as a SchemaType to use an object instead of an array of objects. Here's an example that applies to your situation using SchemaType#validate:

offersInCategory: {
  type: Object,
  validate: object => { //our custom validator, object is the provided object
    let allowedKeys = ['Furniture', 'Household', 'Electronicts', 'Other'];
    let correctKeys = Object.keys(object).every(key => allowedKeys.includes(key)); //make sure all keys are inside `allowedKeys`

    let min = 5;
    let max = 10;
    let correctValues = Object.values(object).every(value => value > min && value < max); //make sure all values are in correct range

    return correctKeys && correctValues; //return true if keys and values pass validation
  }
}

This does not apply duplicate key checks because an object can not have duplicate keys, the later key present just overrides the previous key:

> let foo = { bar: 4, bar: 5}
< Object { bar: 5 }

As you can see, the bar: 4 key that is assigned earlier is overridden by the later key.

Option 2 (with array): You can use SchemaType#validate to implement your custom validation on a certain document path. Here's an example of what you want:

offersInCategory: [{
  validate: {
    validator: array => { //our custom validator, array is the provided array to be validated
      let filtered = array.filter((obj, index, self) => self.findIndex(el => el.category === obj.category) === index); //this removes any duplicates based on object key
      return array.length === filtered.length; //returns true if the lengths are the same; if the lengths aren't the same that means there was a duplicate key and validation fails
    },
    message: 'Detected duplicate keys in {VALUE}!'
  }
  category: {
    type: String, 
    enum: ['Furniture', 'Household', 'Electronicts', 'Other'] //category must be in this enum
  },
  val: {
    type: Number, 
    min: 0, //minimum allowed number is 0
    max: 10 //maximum allowed number is 10
  }
}]

And if you test this, it will get rid of objects in the array with duplicate keys (keeping the earlier one) and checks to see if the array holds only objects with unique category keys.



来源:https://stackoverflow.com/questions/44268350/how-to-validate-object-keys-and-values-in-mongoose-schema

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!