Mongoose - 子文档验证不起作用

时间:2014-05-22 03:02:31

标签: node.js mongodb mongoose

我的架构看起来像这样:

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

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

var minder = new Minder({
  "phones": [{
     details: {
        number: "3343434"
     }
   }]
});

哪些不适用,因为它缺少国家/地区代码和区域代码。事实上,我可以创建一个这样的文档:

var minder = new Minder({
  "phones": [{
    details: {
      "sdf":"sdf"
    }
  }]
});

它验证了。

我错过了什么概念?

2 个答案:

答案 0 :(得分:8)

这里的问题主要在于你如何构建你的"细节"进入这里。因此,尽管您认为自己可能已经做过,但实际上这里的条目类型是一个普通的子文档,或者通常被称为" hash / map或dict"取决于您最熟悉的术语。

严格来说,这些并不是"打字"无论如何,所以没有真正控制"键"你在那里放置。所以你可能想要的是实际上可以用严格类型的方式构建的东西,例如:

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();

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

这里最后一个重点是实现"验证"实际发生了。因此,从您的示例中您只是创建实例,但这不是验证发生的地方。实际发生的唯一地方是当对象实例被保存时#34;并坚持存储。这允许你构建"对象,但不是严格的验证者"传统"类中的对象"感。

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

{ _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)

注意到" log"输出保持"有效"输入但丢弃了未定义的字段,然后"验证"实际上只有当对象实际尝试"保存"时才会出现所需字段

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


如果您真的想要嵌套,请删除"类型"声明如下:

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

验证将对您有用:

{
  "_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.

答案 1 :(得分:0)

在我的嵌套文档中,我使用了此模块mongoose-unique-validator,但是您也可以使用SchemaName.path("key.nestedKey").validate(argument => {})),所以问题是在update上,猫鼬只对查询进行了解析并在没有验证的情况下运行,以验证您可以作为第三个参数{ runValidators: true }