【问题标题】:Mongoose Schema vs Mongo ValidatorMongoose Schema vs Mongo Validator
【发布时间】:2016-07-26 04:28:06
【问题描述】:

Mongo 3.2 有文档验证,我们可以用它来定义模式而不是使用 mongoose 来做吗?例如:

猫鼬

userschema = mongoose.Schema({
   org: String,
   username: String,
   fullname: String, 
   password: String,
   email: String
});

MongoDB

db.createCollection(
   "example",{
     validator:{
       $and:[
         { "org":{$type:"string"}},
         { "username":{$type:"string"}},
         { "fullname":{$type:"double"}},
         {"password":$type:"string"}},
         {"email":{$type:"string"}}
       ]
     }, 
     validationLevel:"strict",
     validationAction:"error"
 })

这两个有什么区别,我们可以像在模式中那样使用验证器提供一个可选字段吗?

【问题讨论】:

  • 它有点过于宽泛,但简而言之,区别在于: 1. MongoDB 验证远没有“客户端”模式定义中可用的功能那么“完整”。 2. MongoDB 模式验证发生在“服务器”而不是“客户端”,因此即使是“原子”操作的修改也可以“在某种程度上”得到验证。 “功能”还处于起步阶段,并且高度依赖“查询表达式”,而“客户端”框架具有完整的语言支持。但当然,所有操作都需要在“客户端”中进行验证。
  • 另外,正如您问题的开场白中所述。这需要 MongoDB 3.2.x 或更高版本。由于那是目前的“最新版本”并且是一个相对较新的版本,所以这并不适合每个人。错误消息也需要“大量工作”,而且远没有像猫鼬这样的客户端框架所能提供的那样具有描述性。

标签: node.js mongodb validation mongoose schema


【解决方案1】:

我同时使用它们,因为它们都有不同的限制:

  • Mongoose 验证器不会在所有类型的更新查询上运行,并且验证器仅在更新文档中具有值的路径上运行,因为验证器无法知道,例如,一个必填字段是否已经在数据库中定义但没有在您客户的记忆中(请参阅issue)。 这是使用 MongoDB 验证器 [除了 Mongoose 验证器] 的主要原因。

    更新验证器仅在 $set$unset 操作上运行(以及 >= 4.8.0 中的 $push$addToSet)。

    因此,您可以在 Mongoose 架构中拥有一个带有 required: true 的字段,但 update 操作实际上不需要该字段! MongoDB 验证器可以解决这个问题:

      db.runCommand({collMod: "collection", validator: {myfield: {$exists: true}}})
    
  • MongoDB 在大多数情况下无法在验证期间引用其他字段。例如,您不能说{field1: {$lte: field2}}。 Mongoose 验证器可以引用其他字段。

    您可以进行一些非常基本的跨字段引用类型:

      {validator: {myfield1: "Value 1", $and: [/* other validators */]}
    

    如果您使用 Mongoose 鉴别器(继承)并且对每种子类型有不同的要求,这会派上用场。

  • MongoDB 不会在验证失败的情况下提供“不错”的错误;它只是说类似writeError: {code: 121, errmsg: "Document failed validation}。 Mongoose 通常会说类似Path 'foo.bar' failed validation

    MongoDB is fixing this in v4.6.

他们共享的能力:

  • 类型验证。 Mongoose 默认尝试将值转换为模式中指定的类型。带有$type 属性的MongoDB 在类型不匹配的情况下会导致验证失败。

  • 最小和最大数值。 Mongoose 在架构上使用 minmax 属性。 MongoDB 使用$lt$lte$gt$gte

  • 字符串枚举。 Mongoose 使用enum: [values]。 MongoDB 使用$in: [values]

  • 字符串长度验证。猫鼬:minlength: 2, maxlength: 10。 MongoDB,使用正则表达式:{fieldname: {$regex: /.{2,10}/}}

  • 数组长度验证。 Mongoose 你必须使用自定义验证器。 MongoDB:{fieldName: {$size: 2}}.

  • 字符串正则表达式匹配。 Mongoose 你必须使用自定义验证器。


第一个要点是主要要点。 MongoDB 没有事务现在有事务,但它确实具有强大(且廉价)的原子更新。您经常无法可靠或安全地使用 MongoDB 读取 -> 更改 -> 验证 -> 写入,因此在这些情况下使用 MongoDB 原生验证器至关重要。

【讨论】:

    【解决方案2】:

    自上次回答以来,MongoDB 4.0 已经发布。

    $jsonSchema 功能现在拥有比基本 mongoose Schema 验证器更多的选项。 (不过,您可以在 mongoose 中添加自定义验证器)。 使用allOfoneOfanyOfnot操作符允许进行复杂匹配,类似于Mongoose判别器。

    使用$exec 命令,可以像这样比较同一文档的两个字段的值:

    db.createCollection("test", {
        validator : {
            $expr : {$gte: ["$budget", "$spend"]}
        }
    })
    

    将验证字段budget 的值必须大于或等于spend 的值。

    (示例改编自mongodb documentation

    MongoDB 仍然存在非信息性错误消息的问题。 就个人而言,我验证了我的数据客户端(如果需要检查唯一性,则向数据库发出请求)。这样,mongodb的验证只有在有并发修改的情况下才会出错(有人在您检查的那一刻和您保存的那一刻之间修改了数据)。当出现 mongodb 错误时,我可以简单地重新运行客户端验证以查看错误。

    我认为 Mongoose 在使用 find-modify-save 策略时已经习惯了它,女巫允许使用所有功能。此策略需要使用版本控制或锁定来防止并发修改。

    当进行原子更新(使用 mongodb 操作符、update 或 findAndModify)时,在 mongodb 验证的当前状态下,我很想不使用 mongoose(或仅将其用于连接管理)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 2018-12-30
      • 2018-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      相关资源
      最近更新 更多