- 英文原版
- 关于中文文档
- 快速上手
- 模式(Schemas)
- 模式类型(SchemaTypes)
- 连接(Connections)
- 模型(Models)
- 文档 (Documents)
- 子文档(Subdocuments)
- 查询 (queries)
- 验证 (validation)
- 中间件 (middleware)
- 填充 (Populate)
- 鉴别器 (Discriminators)
- 插件
- AWS Lambda
- API 文档
- Schema
- Connection
- Document
- Model
- Query
- Aggregate
- SchemaType
- VirtualType
- Error
- Version Compatibility
- FAQ
子文档(Subdocument)
子文档是指嵌套在另一个文档中的文档。 在 Mongoose 中,这意味着你可以在里嵌套另一个 schema。 Mongoose 子文档有两种不同的概念:子文档数组和单个嵌套子文档。
var childSchema = new Schema({ name: 'string' });var parentSchema = new Schema({// Array of subdocumentschildren: [childSchema],// Single nested subdocuments. Caveat: single nested subdocs only work// in mongoose >= 4.2.0child: childSchema});
子文档与普通 document 类似。嵌套 schema 可以有自己的 中间件、自定义检验逻辑、 虚拟值以及其他顶层 schemas 可用的特性。两者主要的不同点是 子文档不能单独保存,他们会在他们的顶级文档保存时保存。
var Parent = mongoose.model('Parent', parentSchema);var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })parent.children[0].name = 'Matthew';// `parent.children[0].save()` 无操作,虽然他触发了中间件// 但是**没有**保存文档。你需要 save 他的父文档parent.save(callback);
子文档跟普通 document 一样有 save 和 validate 中间件。 调用父文档的 save() 会触发其所有子文档的 save() 中间件, validate() 中间件同理。
childSchema.pre('save', function (next) {if ('invalid' == this.name) {return next(new Error('#sadpanda'));}next();});var parent = new Parent({ children: [{ name: 'invalid' }] });parent.save(function (err) {console.log(err.message) // #sadpanda});
子文档的 pre('save') 和 pre('validate') 中间件执行于 顶层 document 的 pre('save') 之前, 顶层 document 的 pre('validate') 之后。 因为 save() 前的验证就是一个内置中间件。(待修改)
// 一下代码顺序打出 1-4var childSchema = new mongoose.Schema({ name: 'string' });childSchema.pre('validate', function(next) {console.log('2');next();});childSchema.pre('save', function(next) {console.log('3');next();});var parentSchema = new mongoose.Schema({child: childSchema,});parentSchema.pre('validate', function(next) {console.log('1');next();});parentSchema.pre('save', function(next) {console.log('4');next();});
查找子文档
每个子文档都有一个默认的 _id 。Mongoose document 数组有一个特别的 id 方法, 这个方法只要传入 _id 就能返回文档数组中特定文档。
var doc = parent.children.id(_id);
添加子文档到数组
Mongoose 数组方法有 push、 unshift、 addToSet、 及其他:
var Parent = mongoose.model('Parent');var parent = new Parent;// create a commentparent.children.push({ name: 'Liesl' });var subdoc = parent.children[0];console.log(subdoc) // { _id: '501d86090d371bab2c0341c5', name: 'Liesl' }subdoc.isNew; // trueparent.save(function (err) {if (err) return handleError(err)console.log('Success!');});
create 方法可以新建子文档但不加入数组。
var newdoc = parent.children.create({ name: 'Aaron' });
删除子文档
每个子文档都有 remove 方法。 另外,对于子文档数组,有一个等效方法 .pull()。 对于单个嵌套子文档,remove() 与把这个文档的值设为 null 等效。
// 等效于 `parent.children.pull(_id)`parent.children.id(_id).remove();// 等效于 `parent.child = null`parent.child.remove();parent.save(function (err) {if (err) return handleError(err);console.log('the subdocs were removed');});
代替声明语法的写法
如果你用对象的数组创建 schema ,mongoose 会自动 为你把对象转换成 schema:
var parentSchema = new Schema({children: [{ name: 'string' }]});// Equivalentvar parentSchema = new Schema({children: [new Schema({ name: 'string' })]});
下一步
这章我们介绍了子文档,下一个章节将会介绍 querying。
mongoose