猫鼬地图中的类型检查

时间:2019-05-31 16:41:22

标签: node.js mongodb mongoose

如果我具有以下架构:

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

从理论上讲,猫鼬在创建新文档时应验证每个UserModule的类型,并确保存在必需的name属性。

但是,如果我创建的用户使用的模块没有name属性:

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

没有引发错误。通常,猫鼬能够正确验证所需的类型。

我可以想到的解决方法包括对每个模块的密钥进行硬编码(并且不使用映射),或者在modules映射上包括一个验证器,以检查所有模块是否都存在必需的密钥,而这些都不是理想。

是否有更好的方法来检查地图值的类型?

1 个答案:

答案 0 :(得分:1)

您正在提供一个值...这是有效的Map定义:

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

Map尚未验证。只有键始终是字符串,Map才会验证。考虑以下模式:

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

如果您需要地图,请确保没有默认值等。

您也可以查看map tests @ github以获得更多见识

在这些测试中,您还可以看到如何制作复杂的嵌套地图:

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

这将按预期保存:

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

尝试保存此操作将失败,因为需要要求bar

var author = new Author({
  "pages" : {
    "baz" : { "foo" : 1 }  // <-- no bar!
  }
});