【问题标题】:Type Checking in Mongoose Maps猫鼬地图中的类型检查
【发布时间】:2019-10-17 07:51:00
【问题描述】:

如果我有以下架构:

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

理论上,mongoose 应该在我创建新文档时验证每个 UserModule 的类型,确保存在所需的 name 属性。

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

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

没有抛出错误。通常,mongoose 能够正确验证所需的类型。

我能想到的解决方法包括对每个模块的键进行硬编码(而不是使用映射)或在 modules 映射上包含一个验证器,以检查所有模块是否存在所需的键,但都不是理想的。

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

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

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

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

    至于Map 没有验证。 Map 确实验证 values 只是因为键始终是字符串。考虑这个架构:

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

    【讨论】:

    • 我想到了这一点,但考虑到我将来可以更改 name 属性的架构,这并不理想。此外(不是问题的一部分),但默认值也不适用于地图值,这与地图值没有验证有关。
    • 我认为如果映射值是NumberString 等基本类型,它会起作用,但如果我尝试使用任何对象结构对其进行强类型化,那么它就会出现问题。例如,尝试使用of: { type: { id: Number, name: String } }
    猜你喜欢
    • 2015-03-27
    • 2017-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    • 2015-07-28
    • 1970-01-01
    • 2019-01-16
    相关资源
    最近更新 更多