# 模式（schemas）

> 原文：[Schemas](http://mongoosejs.com/docs/guide.html)\
> 翻译：小虾米（QQ:509129）

## schemas

> 如果你还没有开始，请花一分钟阅读[快速入门](http://mongoosejs.com/docs/index.html)学习Mongoose 是如何工作的。如果你是从3.x迁移到4.x，请花一点时间来阅读[迁移指南](http://mongoosejs.com/docs/migration.html)。

### 定义你的schema

Mongoose的一切都始于一个Schema。每个schema映射到MongoDB的集合(collection)和定义该集合(collection)中的文档的形式。

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

var blogSchema = new Schema({
  title:  String,
  author: String,
  body:   String,
  comments: [{ body: String, date: Date }],
  date: { type: Date, default: Date.now },
  hidden: Boolean,
  meta: {
    votes: Number,
    favs:  Number
  }
});
```

如果您想稍后添加额外的键（keys），使用[Schema#add](http://mongoosejs.com/docs/api.html#schema_Schema-add)方法。

在我们的blogSchema每个key在我们的文件将被转换为相关[SchemaType](http://mongoosejs.com/docs/api.html#schematype_SchemaType)定义一个属性。例如，我们定义了一个标题(title)将被转换为[字符串(String)](http://mongoosejs.com/docs/api.html#schema-string-js)的 SchemaType 并将日期(date)转换为日期的 SchemaType 。键（keys）也可以被指定嵌套的对象，包含进一步的键/类型定义（例如，上面的 `meta`属性）。

允许使用的SchemaTypes：

* String
* Number
* Date
* Buffer
* Boolean
* Mixed
* ObjectId
* Array

阅读更多关于他们在[这里](http://mongoosejs.com/docs/schematypes.html)。

Schemas不仅定义了文档和属性的结构，还定义了文档[实例方法](http://mongoosejs.com/docs/guide.html#methods)、静态[模型方法](http://mongoosejs.com/docs/guide.html#statics)、[复合索引](http://mongoosejs.com/docs/guide.html#indexes)和文档被称为[中间件](http://mongoosejs.com/docs/middleware.html)的生命周期钩子。

### 创建一个模型

使用我们的schema定义，我们需要将我们的blogschema转成我们可以用的模型。为此，我们通过`mongoose.model(modelName, schema)`：

```javascript
var Blog = mongoose.model('Blog', blogSchema);
// ready to go!
```

### 实例方法

模型的实例是[文档（documents）](http://mongoosejs.com/docs/documents.html)。文档有许多自己[内置的实例方法](http://mongoosejs.com/docs/api.html#document-js)。我们也可以定义我们自己的自定义文档实例方法。

```javascript
// define a schema
var animalSchema = new Schema({ name: String, type: String });

// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
  return this.model('Animal').find({ type: this.type }, cb);
};
```

现在我们所有的animal的实例有一个`findsimilartypes`方法可用。

```javascript
var Animal = mongoose.model('Animal', animalSchema);
var dog = new Animal({ type: 'dog' });

dog.findSimilarTypes(function(err, dogs) {
  console.log(dogs); // woof
});
```

> 重写默认的mongoose文档方法可能会导致不可预测的结果。[看到更多的细节](http://mongoosejs.com/docs/api.html#schema_Schema.reserved)。

### 静态方法（Statics）

给一个模型添加静态方法的也是很简单。继续我们的`animalschema`：

```javascript
// assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function(name, cb) {
  return this.find({ name: new RegExp(name, 'i') }, cb);
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function(err, animals) {
  console.log(animals);
});
```

### 查询助手

您还可以像实例方法那样添加查询辅助功能，这是，但对于mongoose的查询。查询辅助方法可以让你扩展mongoose链式查询生成器API。

```javascript
animalSchema.query.byName = function(name) {
  return this.find({ name: new RegExp(name, 'i') });
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.find().byName('fido').exec(function(err, animals) {
  console.log(animals);
});
```

### 索引（Indexes）

MongoDB支持 [secondary indexes](http://docs.mongodb.org/manual/indexes/) 。与 mongoose，我们定义这些indexes在我们的Schema的在路径级别或schema级别。在创建[复合索引](http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeys)时，在 schema 级别上定义索引是必要的。

> 译者注：[普通索引（index）](http://mongoosejs.com/docs/api.html#schematype_SchemaType-index)，[唯一索引（unique）](http://mongoosejs.com/docs/api.html#schematype_SchemaType-unique)，[稀疏索引](http://mongoosejs.com/docs/api.html#schematype_SchemaType-sparse)，[时效索引（expires）](http://mongoosejs.com/docs/api.html#schema_date_SchemaDate-expires)

```javascript
var animalSchema = new Schema({
  name: String,
  type: String,
  tags: { type: [String], index: true } // field level
});

animalSchema.index({ name: 1, type: -1 }); // schema level
```

> 当应用程序启动时，Mongoose为你的schema定义的每个索引自动调用`ensureindex`。Mongoose会按照每个索引的顺序调用ensureindex，并在模型上发出一个`'index'`事件，当所有的`ensureindex`调用返回成功或当时有一个错误返回。虽然很好的开发，建议这种行为禁用在生产中，因为索引创建可以导致一个[显着的性能影响](http://docs.mongodb.org/manual/core/indexes/#index-creation-operations)。通过设置schema的`autoIndex`选项为`false`，或对全局连接的设置选项`config.autoindex`为`false`。

```javascript
mongoose.connect('mongodb://user:pass@localhost:port/database', { config: { autoIndex: false } });
// or  
mongoose.createConnection('mongodb://user:pass@localhost:port/database', { config: { autoIndex: false } });
// or
animalSchema.set('autoIndex', false);
// or
new Schema({..}, { autoIndex: false });
```

查看[ Model#ensureIndexes](http://mongoosejs.com/docs/api.html#model_Model.ensureIndexes) 方法。

### 虚拟属性

[虚拟属性](http://mongoosejs.com/docs/api.html#schema_Schema-virtual) 是文档属性，您可以获取和设置但不保存到MongoDB。用于格式化或组合字段，从而制定者去组成一个单一的值为存储多个值是有用的。

```javascript
// define a schema
var personSchema = new Schema({
  name: {
    first: String,
    last: String
  }
});

// compile our model
var Person = mongoose.model('Person', personSchema);

// create a document
var bad = new Person({
    name: { first: 'Walter', last: 'White' }
});
```

假设我们想打印bad的全名。我们可以这样做：

```javascript
console.log(bad.name.first + ' ' + bad.name.last); // Walter White
```

或者我们可以在personschema定义 [ 虚拟属性的getter ](http://mongoosejs.com/docs/api.html#virtualtype_VirtualType-get)，这样我们不需要每次写出这个字符串的拼接：

```javascript
personSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});
```

现在，我们进入我们的虚拟”的`"name.full"`资源的时候，我们将调用getter函数的返回值：

```javascript
console.log('%s is insane', bad.name.full); // Walter White is insane
```

注意，如果产生的记录转换为一个对象或JSON，virtuals不包括默认。通过`virtuals`：`true`是`toobject()`或`tojson()`他们返回值。

这也是不错的，能够通过`this.name.full`设置`this.name.first`和`this.name.last`。例如，如果我们想respectively改变`bad`的`name.first`和`name.last`为`'Breaking'`和`'Bad'`，只需要：

```javascript
bad.name.full = 'Breaking Bad';
```

Mongoose让你这样做也是通过[虚拟属性的setter](http://mongoosejs.com/docs/api.html#virtualtype_VirtualType-set)：

```javascript
personSchema.virtual('name.full').set(function (name) {
  var split = name.split(' ');
  this.name.first = split[0];
  this.name.last = split[1];
});

...

mad.name.full = 'Breaking Bad';
console.log(mad.name.first); // Breaking
console.log(mad.name.last);  // Bad
```

`[虚拟属性的setter` 在其他验证之前使用。因此，上面的例子仍然可以工作，即使第一个和最后一个name字段是必需的。

只有非虚拟属性工作作为查询的一部分和字段选择。

### 选项（Options）

Schemas有几个可配置的选项，可以直接传递给构造函数或设置：

```javascript
new Schema({..}, options);

// or

var schema = new Schema({..});
schema.set(option, value);
```

有效的选项：

* [autoIndex](http://mongoosejs.com/docs/guide.html#autoIndex)
* [capped](http://mongoosejs.com/docs/guide.html#capped)
* [collection](http://mongoosejs.com/docs/guide.html#collection)
* [emitIndexErrors](http://mongoosejs.com/docs/guide.html#emitIndexErrors)
* [id](http://mongoosejs.com/docs/guide.html#id)
* [\_id](http://mongoosejs.com/docs/guide.html#_id)
* [minimize](http://mongoosejs.com/docs/guide.html#minimize)
* [read](http://mongoosejs.com/docs/guide.html#read)
* [safe](http://mongoosejs.com/docs/guide.html#safe)
* [shardKey](http://mongoosejs.com/docs/guide.html#shardKey)
* [strict](http://mongoosejs.com/docs/guide.html#strict)
* [toJSON](http://mongoosejs.com/docs/guide.html#toJSON)
* [toObject](http://mongoosejs.com/docs/guide.html#toObject)
* [typeKey](http://mongoosejs.com/docs/guide.html#typeKey)
* [validateBeforeSave](http://mongoosejs.com/docs/guide.html#validateBeforeSave)
* [versionKey](http://mongoosejs.com/docs/guide.html#versionKey)
* [skipVersioning](http://mongoosejs.com/docs/guide.html#versionKey)
* [timestamps](http://mongoosejs.com/docs/guide.html#versionKey)

#### 选项: autoIndex

在应用程序启动时，Mongoose在你的Schema为每一个索引声明发送一个`ensureIndex`命令。在Mongoose V3版本时，索引是默认在后台创建。如果你想禁用自动创建和手动创建索引时，将你的Schemas自动索引（autoIndex）选项设置为`false`和在你的模型使用`ensureindexes`方法。

```javascript
var schema = new Schema({..}, { autoIndex: false });
var Clock = mongoose.model('Clock', schema);
Clock.ensureIndexes(callback);
```

#### 选项: bufferCommands

默认情况下，mongoose缓冲命令一直存在直到驱动设法重新连接。禁用缓冲，设置`buffercommands`为`false`。

```javascript
var schema = new Schema({..}, { bufferCommands: false });
```

#### 选项: capped

Mongoose支持 MongoDBs [capped](http://www.mongodb.org/display/DOCS/Capped+Collections)集合。指定的MongoDB集合被封顶、设置封顶（capped）选项为文档的最大[字节](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-size.)数。

```javascript
new Schema({..}, { capped: 1024 });
```

capped选项也可以设置一个对象，如果你想通过附加选项，像[Max](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-max)或[autoindexid](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-autoIndexId)。在这种情况下，您必须显式地通过size选项。

```javascript
new Schema({..}, { capped: { size: 1024, max: 1000, autoIndexId: true } });
```

#### 选项: collection

Mongoose默认情况下通过模型名称的`utils.tocollectionname`方法产生的集合名称。这种方法复数名称。设置此选项，如果您需要不同的名称集合。

```javascript
var dataSchema = new Schema({..}, { collection: 'data' });
```

#### 选项: emitIndexErrors

默认情况下，mongoose会建立您在您的模式中指定的任何索引，并在模型中发出一个'index'事件，返回成功或错误。

```javascript
MyModel.on('index', function(error) {
  /* If error is truthy, index build failed */
});
```

然而，这使得它很难捕捉当您的索引建立失败。`emitIndexErrors`选项可是是你轻松看到索引建立失败。如果此选项打开，当索引建立失败时mongoose会同时在模型上发出一个`'error'`事件。

```javascript
MyModel.schema.options.emitIndexErrors; // true
MyModel.on('error', function(error) {
  // gets an error whenever index build fails
});
```

如果一个错误事件被触发并没有听众，Node.js的内置事件抛出一个异常，所以很容易配置快速失败应用程序时的索引构建失败。

#### 选项: id

Mongoose将你schemas id virtual getter 默认返回的文档\_id场转换为字符串，或者ObjectIds，它的哈希字符串。如果你不想要一个Iid getter加到你的schema，你可以它在schema构建的时通过这个选项禁用。

```javascript
// default behavior
var schema = new Schema({ name: String });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'

// disabled id
var schema = new Schema({ name: String }, { id: false });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // undefined
```

#### 选项: \_id

Mongoose默认分配你的每个模式一个\_id字段如果没有一个传递到[模式](http://mongoosejs.com/docs/api.html#schema-js)构造函数。类型分配一个[objectID](http://mongoosejs.com/docs/api.html#schema_Schema.Types)配合MongoDB的默认行为。如果你不想要一个\_id加到你的模式时，你可以使用这个选项禁用它。

您只能在子文档中使用此选项。Mongoose不能保存文档而不知道其id，所以你会保存一个没有\_id文档会得到一个错误。

```javascript
// default behavior
var schema = new Schema({ name: String });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p); // { _id: '50341373e894ad16347efe01', name: 'mongodb.org' }

// disabled _id
var childSchema = new Schema({ name: String }, { _id: false });
var parentSchema = new Schema({ children: [childSchema] });

var Model = mongoose.model('Model', parentSchema);

Model.create({ children: [{ name: 'Luke' }] }, function(error, doc) {
  // doc.children[0]._id will be undefined
});
```

#### 选项: minimize

Mongoose，默认情况下，“minimize”模式通过删除空对象。

```javascript
var schema = new Schema({ name: String, inventory: {} });
var Character = mongoose.model('Character', schema);

// will store `inventory` field if it is not empty
var frodo = new Character({ name: 'Frodo', inventory: { ringOfPower: 1 }});
Character.findOne({ name: 'Frodo' }, function(err, character) {
  console.log(character); // { name: 'Frodo', inventory: { ringOfPower: 1 }}
});

// will not store `inventory` field if it is empty
var sam = new Character({ name: 'Sam', inventory: {}});
Character.findOne({ name: 'Sam' }, function(err, character) {
  console.log(character); // { name: 'Sam' }
});
```

这种行为可以通过设置minimize选项为false。它将存储空的对象。

```javascript
var schema = new Schema({ name: String, inventory: {} }, { minimize: false });
var Character = mongoose.model('Character', schema);

// will store `inventory` if empty
var sam = new Character({ name: 'Sam', inventory: {}});
Character.findOne({ name: 'Sam' }, function(err, character) {
  console.log(character); // { name: 'Sam', inventory: {}}
});
```

#### 选项: read

允许设置[query#read](http://mongoosejs.com/docs/api.html#query_Query-read) 选项在模式层面，为我们提供一种方法来使用默认值[ReadPreferences](http://docs.mongodb.org/manual/applications/replication/#replica-set-read-preference)为模型的所有查询。

```javascript
var schema = new Schema({..}, { read: 'primary' });            // also aliased as 'p'
var schema = new Schema({..}, { read: 'primaryPreferred' });   // aliased as 'pp'
var schema = new Schema({..}, { read: 'secondary' });          // aliased as 's'
var schema = new Schema({..}, { read: 'secondaryPreferred' }); // aliased as 'sp'
var schema = new Schema({..}, { read: 'nearest' });            // ali
```

每个首选的别名允许替代而不是必须输入'secondaryPreferred'并得到拼写错误，我们可以简单地通过'sp'。

读选项还允许我们指定标记集。这些告诉[驱动程序](https://github.com/mongodb/node-mongodb-native/)的副本集的成员应该尝试读取。阅读更多关于标签集[这里](http://docs.mongodb.org/manual/applications/replication/#tag-sets)和[这里](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences)。

注意：您也可以指定驱动程序读取优先策略选择当连接时：

```javascript
// pings the replset members periodically to track network latency
var options = { replset: { strategy: 'ping' }};
mongoose.connect(uri, options);

var schema = new Schema({..}, { read: ['nearest', { disk: 'ssd' }] });
mongoose.model('JellyBean', schema);
```

#### 选项: safe

这个选项是通过与MongoDB所有操作并指定如果错误应该回到我们的回调以及调写行为。

```javascript
var safe = true;
new Schema({ .. }, { safe: safe });
```

默认设置为true应用为所有模式，可以保证任何发生的错误被传递回我们的回调函数。通过设置安全的东西像`{ j: 1, w: 2, wtimeout: 10000 }`，我们可以保证写致力于MongoDB journal (j: 1)，至少有2个副本 (w: 2)，并写会超时如果需要超过10秒 (wtimeout: 10000)。错误仍然会被传递给我们的回调。

注：在3.6.x，你也需要把[版本](http://mongoosejs.com/docs/guide.html#versionKey)删掉。在 3.7.x 及以上版本会自动被禁用当安全设置为false。

\*\*注：此设置将覆盖任何设置指定通过传递数据库选项，同时[创建一个连接](http://mongoosejs.com/docs/api.html#index_Mongoose-createConnection)。

还有其他写的问题，如`{ w: "majority" }`。看MongoDB[文档](http://www.mongodb.org/display/DOCS/getLastError+Command)详情。

```javascript
var safe = { w: "majority", wtimeout: 10000 };
new Schema({ .. }, { safe: safe });
```

#### 选项: shardKey

shardkey选项是用来当我们有一个分片的MongoDB架构。每个分片集提供一个shard key必须存在于所有的插入/更新操作。我们只需要设置此模式选项相同的shard key，我们将所有设置。

```javascript
new Schema({ .. }, { shardKey: { tag: 1, name: 1 }})
```

> 注意，Mongoose不发送`shardcollection`命令给你。你必须配置你自己的分片。

#### 选项: strict

严格选项（默认启用），确保传递给我们的模型构造函数的值没有被指定在我们的模式中，不会被保存到数据库中。

```javascript
var thingSchema = new Schema({..})
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is not saved to the db

// set to false..
var thingSchema = new Schema({..}, { strict: false });
var thing = new Thing({ iAmNotInTheSchema: true });
thing.save(); // iAmNotInTheSchema is now saved to the db!!
```

使用`doc.set()`来设置属性值这样也会起作用。

```javascript
var thingSchema = new Schema({..})
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing;
thing.set('iAmNotInTheSchema', true);
thing.save(); // iAmNotInTheSchema is not saved to the db
```

这个值可以被覆盖，在模型实例层通过第二个尔参数：

```javascript
var Thing = mongoose.model('Thing');
var thing = new Thing(doc, true);  // enables strict mode
var thing = new Thing(doc, false); // disables strict mode
```

严格的选项也可能被设置为“throw”，这将导致错误产生，而不是丢弃坏数据。

注意：不要设置为false，除非你有很好的理由。

注：在mongoose v2默认是false的。

注意：任何键/值设置在实例上

注意：不管在不在你的模式中存在的任何键/值的实例将被忽略，无论模式选项。

```javascript
var thingSchema = new Schema({..})
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing;
thing.iAmNotInTheSchema = true;
thing.save(); // iAmNotInTheSchema is never saved to the db
```

#### 选项: toJSON

Exactly the same as the toObject option but only applies when the documents toJSON method is called.

完全一样的toObject选项，但只适用于当文件tojson方法称为。

```javascript
var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
  return v + ' is my name';
});
schema.set('toJSON', { getters: true, virtuals: false });
var M = mongoose.model('Person', schema);
var m = new M({ name: 'Max Headroom' });
console.log(m.toObject()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom' }
console.log(m.toJSON()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
// since we know toJSON is called whenever a js object is stringified:
console.log(JSON.stringify(m)); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" }
```

要查看所有可用的toJSON/toObject 选项，读[这](http://mongoosejs.com/docs/api.html#document_Document-toObject)。

#### 选项: toObject

文档有一个[toObject](http://mongoosejs.com/docs/api.html#document_Document-toObject)的方法将mongoose文档转成成到一个普通的JavaScript对象。此方法接受一些选项。代替这些选项在一个文档的基础上，我们可以声明这里的选项，并将其应用到所有的这个模式文档为默认。

让所有的虚函数显示在你的console.log输出，设置toObject选项为 { getters: true }：

```javascript
var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
  return v + ' is my name';
});
schema.set('toObject', { getters: true });
var M = mongoose.model('Person', schema);
var m = new M({ name: 'Max Headroom' });
console.log(m); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
```

要查看所有可用的toObject选择，读[这](http://mongoosejs.com/docs/api.html#document_Document-toObject)。

#### 选项: typeKey

默认情况下，如果在你的模式中你有一个对象‘type’为键，mongoose只会把它理解为一种类型声明。

```javascript
// Mongoose interprets this as 'loc is a String'
var schema = new Schema({ loc: { type: String, coordinates: [Number] } });
```

然而，对于像GeoJSON这样的应用程序，‘typ’属性是很重要的。如果你想控制键mongoose用找到的类型声明，设置‘typeKey’模式选项。

```javascript
var schema = new Schema({
  // Mongoose interpets this as 'loc is an object with 2 keys, type and coordinates'
  loc: { type: String, coordinates: [Number] },
  // Mongoose interprets this as 'name is a String'
  name: { $type: String }
}, { typeKey: '$type' }); // A '$type' key means this object is a type declaration
```

#### 选项: validateBeforeSave

默认情况下，在将文档保存到数据库之前，文档将自动验证。这是为了防止保存无效的文档。如果你想手动处理验证，能够保存不通过验证的对象，您可以设置validatebeforesave为false。

```javascript
var schema = new Schema({ name: String });
schema.set('validateBeforeSave', false);
schema.path('name').validate(function (value) {
    return v != null;
});
var M = mongoose.model('Person', schema);
var m = new M({ name: null });
m.validate(function(err) {
    console.log(err); // Will tell you that null is not allowed.
});
m.save(); // Succeeds despite being invalid
```

#### 选项: versionKey

versionKey是一个设置在每个文档上的属性当第一次被Mongoose创建时。此键值包含文档的内部修订版。versionkey选项是一个字符串，表示使用版本控制路径。默认的是`__v`。如果这种与您的应用程序冲突你可以配置：

```javascript
var schema = new Schema({ name: 'string' });
var Thing = mongoose.model('Thing', schema);
var thing = new Thing({ name: 'mongoose v3' });
thing.save(); // { __v: 0, name: 'mongoose v3' }

// customized versionKey
new Schema({..}, { versionKey: '_somethingElse' })
var Thing = mongoose.model('Thing', schema);
var thing = new Thing({ name: 'mongoose v3' });
thing.save(); // { _somethingElse: 0, name: 'mongoose v3' }
```

文档版本也可以通过设置versionkey为false禁用。不禁用版本除非你[知道你正在做什么](http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning)。

```javascript
new Schema({..}, { versionKey: false });
var Thing = mongoose.model('Thing', schema);
var thing = new Thing({ name: 'no versioning please' });
thing.save(); // { name: 'no versioning please' }
```

#### 选项: skipVersioning

skipversioning允许从versioning扣除路径（例如，内部的修改不会增加即使这些路径更新）。不要这样做，除非你知道你在做什么。对于子文档，使用完全限定的路径将此文件包含在父文档中。

```javascript
new Schema({..}, { skipVersioning: { dontVersionMe: true } });
thing.dontVersionMe.push('hey');
thing.save(); // version is not incremented
```

#### 选项: timestamps

如果设置时间戳，mongoose分配`createdAt`和`updatedAt`字段到你的模式汇总，类型指定为Date。

By default, the name of two fields are createdAt and updatedAt, custom the field name by setting timestamps.createdAt and timestamps.updatedAt.

默认情况下，两个字段的名字是`createdAt`和`updatedAt`，自定义字段名称设置`timestamps.createdat`和`timestamps.updatedat`。

```javascript
var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing();
thing.save(); // `created_at` & `updatedAt` will be included
```

#### 选项: useNestedStrict

在mongoose 4中，`update()`和`findoneandupdate()`只检查顶层模式的严格模式设置。

```javascript
var childSchema = new Schema({}, { strict: false });
var parentSchema = new Schema({ child: childSchema }, { strict: 'throw' });
var Parent = mongoose.model('Parent', parentSchema);
Parent.update({}, { 'child.name': 'Luke Skywalker' }, function(error) {
  // Error because parentSchema has `strict: throw`, even though
  // `childSchema` has `strict: false`
});

var update = { 'child.name': 'Luke Skywalker' };
var opts = { strict: false };
Parent.update({}, update, opts, function(error) {
  // This works because passing `strict: false` to `update()` overwrites
  // the parent schema.
});
```

如果你设置`useNestedStrict`为true，mongoose会使用子模式的严格选项铸造更新。

```javascript
var childSchema = new Schema({}, { strict: false });
var parentSchema = new Schema({ child: childSchema },
  { strict: 'throw', useNestedStrict: true });
var Parent = mongoose.model('Parent', parentSchema);
Parent.update({}, { 'child.name': 'Luke Skywalker' }, function(error) {
  // Works!
});
```

### Pluggable

模式也可允许我们[打包](http://mongoosejs.com/docs/plugins.html)成可重用的功能[插件](http://plugins.mongoosejs.io/)，可以与社区或是你的项目之间共享。

### 下一步

既然我们已经掌握了`Schemas`，让我们看看[模式类型（SchemaTypes）](http://mongoosejs.com/docs/schematypes.html)。
