Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Checking in Mongoose Maps

If I have the following schema:

const userSchema = new mongoose.Schema({
  modules: {
    type: Map,
    of: {
      name: {
        type: String,
        required: true
      }
    }
  }
})

Theoretically, mongoose should validate the type of each UserModule when I create a new document, ensuring the required name property is present.

However, if I create a user with a module without the name property:

await User.create({ modules: { example: {} } })

No error is thrown. Normally, mongoose is able to correctly validate for required types.

Workarounds I can think of include either hardcoding the keys for each module (and not use a map) or including a validator on the modules map to check all modules have the required keys are present, none of which are ideal.

Is there a better way to check the type of map values?

like image 739
Frank Avatar asked Sep 15 '26 19:09

Frank


1 Answers

You are providing a value ... this is a valid Map definition:

await User.create({ 
  modules: { 
    example: {}   // <-- this is a valid. Key is `example` value is {}
  } 
})

As far as Map not having validation. Map does validate the values only since the keys are always strings. Consider this schema:

var AuthorSchema = new Schema({
  books: {
    type: Map,
    of: { type: Number },
    default: { "first book": 100 },  // <-- set default values
    required: true                   // <-- set required
  }
})

// after mongoose.model('Author', AuthorSchema) etc ....

var author1 = new Author({ books: { 'book one': 200 } })
author1.save() // <-- On save this works

var author2 = new Author({ books: { 'book one': "foo" } }) 
author2.save() // <-- This fails validation with "Cast to number failed ..."

var author1 = new Author()
author1.save() // <-- default would set values and that would pass the `required` validation

If you want to require the map make sure you do not have values in the default etc.

You can also review the map tests @ github for more insight

And in those tests you can also see how to do a complex nested map:

var AuthorSchema = new Schema({
  pages: {
    type: Map,
    of: new mongoose.Schema({   // <-- just nest another schema
      foo: { type: Number },  // <-- set your type, default, required etc
      bar: { type: String, required: true } // <-- required!
    }, { _id: false }),
    default: { 
      'baz': { 
        foo: 100, bar: 'moo'  // <-- set your defaults
      } 
    }
  }
})

This would save as expected this:

{
    "_id" : ObjectId("5cf1cf4b7f67711963e2406d"),
    "pages" : {
        "baz" : {
            "foo" : 100,
            "bar" : "moo"
        }
    }
}

Trying to save this would fail since bar is required:

var author = new Author({
  "pages" : {
    "baz" : { "foo" : 1 }  // <-- no bar!
  }
});
like image 110
Akrion Avatar answered Sep 19 '26 06:09

Akrion



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!