Mongoose - 子文档验证不起作用

Dom*_*mra 6 mongoose mongodb node.js

我有一个看起来像这样的架构:

var minderSchema = mongoose.Schema({
  phones: {type: [{
    details: {
      type: {
        country_code: { type: String, required: true },
        region_code: { type: String, required: true },
        number: { type: Number, required: true }
      },
      required: true
    },
  }], required: true},
})
Run Code Online (Sandbox Code Playgroud)

那是......一个监视器由一系列电话组成(这是必需的).每部手机必须有国家代码,地区代码和号码.但验证似乎不起作用.即我可以创建:

var minder = new Minder({
  "phones": [{
     details: {
        number: "3343434"
     }
   }]
});
Run Code Online (Sandbox Code Playgroud)

这应该不起作用,因为它缺少国家代码和区域代码.实际上我可以创建这样的文档:

var minder = new Minder({
  "phones": [{
    details: {
      "sdf":"sdf"
    }
  }]
});
Run Code Online (Sandbox Code Playgroud)

它验证了.

我错过了什么概念?

Nei*_*unn 9

这里的问题主要在于你如何构建你的"细节"条目.因此,尽管您认为自己可能已经做了什么,但实际上这里的条目类型是一个普通的子文档,或者通常被称为"哈希/地图或字典"的内容,具体取决于您最熟悉的术语.

这些并不是严格意义上的"打字",所以没有真正控制你放在那里的"钥匙".所以你可能想要的东西实际上可以用严格类型的方式构造,例如:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');

var phonesSchema = new Schema({
  country_code: { type: String, required: true },
  region_code: { type: String, required: true },
  number: { type: String, required: true }
});

var minderSchema = new Schema({

  phones:[phonesSchema]

});


var Minder = mongoose.model( 'Minder', minderSchema );

var minder = new Minder({
  "phones": [{ "number": "12345", "bill": "45678" }]
});

console.log( JSON.stringify( minder, undefined, 2 ) );


minder.save();
Run Code Online (Sandbox Code Playgroud)

这不仅区分了模式定义(这很方便和干净),而且现在你有一个明确定义的"子类型",可以对条目进行验证.如果需要,你可以扩展它,但我通常认为这是更清洁的形式.

这里的最后一点重要的是实现"验证"实际发生的位置.因此,从您的示例中您只是创建实例,但这不是验证发生的地方.实际发生的唯一地方是对象实例被"保存"并持久存储.这允许您"构建"对象,但不是传统"类"意义上的对象的严格"验证器".

所以运行上面的代码片段,你得到这个输出:

{ _id: 537d7c71d4d04b65174d0c00,
  phones: [ { number: '12345', _id: 537d7c71d4d04b65174d0c01 } ] }

events.js:72
        throw er; // Unhandled 'error' event
          ^
No listeners detected, throwing. Consider adding an error listener to your connection.
ValidationError: Path `region_code` is required., Path `country_code` is required.
    at model.Document.invalidate (/home/neillunn/node_modules/mongoose/lib/document.js:1009:32)
    at EmbeddedDocument.invalidate (/home/neillunn/node_modules/mongoose/lib/types/embedded.js:178:19)
    at /home/neillunn/node_modules/mongoose/lib/document.js:958:16
    at validate (/home/neillunn/node_modules/mongoose/lib/schematype.js:610:7)
    at /home/neillunn/node_modules/mongoose/lib/schematype.js:627:9
    at Array.forEach (native)
    at SchemaString.SchemaType.doValidate     (/home/neillunn/node_modules/mongoose/lib/schematype.js:614:19)
    at /home/neillunn/node_modules/mongoose/lib/document.js:956:9
    at process._tickCallback (node.js:419:13)
    at Function.Module.runMain (module.js:499:11)
Run Code Online (Sandbox Code Playgroud)

他指出,"日志"输出有保持"有效"条目,而是被忽略不定义的字段,然后在"验证"真的只发生在必填字段只有当对象实际尝试"拯救".

因此,请考虑您的结构以及实施验证的实际情况.尝试添加未定义的字段不会出错,它只会丢弃.省略"必需"字段仅在对象持久化时检查,这允许您有时间构建它.这些不是"类构造函数"类型的参数,而是出于不同的目的.


如果您真的想要嵌套,请删除"type"声明,如下所示:

var phonesSchema = new Schema({
  details: {
    country_code: { type: String, required: true },
    region_code: { type: String, required: true },
    number: { type: String, required: true }
  }
});
Run Code Online (Sandbox Code Playgroud)

验证将适用于您:

{
  "_id": "537d9e6d5b433f8745547f52",
  "phones": [
    {
      "_id": "537d9e6d5b433f8745547f53",
      "details": {
        "number": "12345"
      }
    }
  ]
}

events.js:72
    throw er; // Unhandled 'error' event
          ^
No listeners detected, throwing. Consider adding an error listener to your connection.
ValidationError: Path `details.region_code` is required., Path `details.country_code` is required.
Run Code Online (Sandbox Code Playgroud)