添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

模式(schemas)

原文: Schemas 翻译:小虾米(QQ:509129)

schemas

如果你还没有开始,请花一分钟阅读 快速入门 学习Mongoose 是如何工作的。如果你是从3.x迁移到4.x,请花一点时间来阅读 迁移指南

定义你的schema

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

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 方法。

在我们的blogSchema每个key在我们的文件将被转换为相关 SchemaType 定义一个属性。例如,我们定义了一个标题(title)将被转换为 字符串(String) 的 SchemaType 并将日期(date)转换为日期的 SchemaType 。键(keys)也可以被指定嵌套的对象,包含进一步的键/类型定义(例如,上面的 meta 属性)。

允许使用的SchemaTypes:

  • String

  • Number

  • Date

  • Buffer

  • Boolean

  • Mixed

  • ObjectId

  • Array

阅读更多关于他们在 这里

Schemas不仅定义了文档和属性的结构,还定义了文档 实例方法 、静态 模型方法 复合索引 和文档被称为 中间件 的生命周期钩子。

创建一个模型

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

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

实例方法

模型的实例是 文档(documents) 。文档有许多自己 内置的实例方法 。我们也可以定义我们自己的自定义文档实例方法。

// 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 方法可用。

var Animal = mongoose.model('Animal', animalSchema);
var dog = new Animal({ type: 'dog' });
dog.findSimilarTypes(function(err, dogs) {
  console.log(dogs); // woof
});

重写默认的mongoose文档方法可能会导致不可预测的结果。 看到更多的细节

静态方法(Statics)

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

// 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。

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 。与 mongoose,我们定义这些indexes在我们的Schema的在路径级别或schema级别。在创建 复合索引 时,在 schema 级别上定义索引是必要的。

译者注: 普通索引(index) 唯一索引(unique) 稀疏索引 时效索引(expires)

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 调用返回成功或当时有一个错误返回。虽然很好的开发,建议这种行为禁用在生产中,因为索引创建可以导致一个 显着的性能影响 。通过设置schema的 autoIndex 选项为 false ,或对全局连接的设置选项 config.autoindex false

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 方法。

虚拟属性

虚拟属性 是文档属性,您可以获取和设置但不保存到MongoDB。用于格式化或组合字段,从而制定者去组成一个单一的值为存储多个值是有用的。

// 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的全名。我们可以这样做:

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

或者我们可以在personschema定义 虚拟属性的getter ,这样我们不需要每次写出这个字符串的拼接:

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

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

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' ,只需要:

bad.name.full = 'Breaking Bad';

Mongoose让你这样做也是通过 虚拟属性的setter

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有几个可配置的选项,可以直接传递给构造函数或设置:

new Schema({..}, options);
// or
var schema = new Schema({..});
schema.set(option, value);

有效的选项:

选项: autoIndex

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

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

选项: bufferCommands

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

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

选项: capped

Mongoose支持 MongoDBs capped 集合。指定的MongoDB集合被封顶、设置封顶(capped)选项为文档的最大 字节 数。

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

capped选项也可以设置一个对象,如果你想通过附加选项,像 Max autoindexid 。在这种情况下,您必须显式地通过size选项。

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

选项: collection

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

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

选项: emitIndexErrors

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

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

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

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构建的时通过这个选项禁用。

// 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字段如果没有一个传递到 模式 构造函数。类型分配一个 objectID 配合MongoDB的默认行为。如果你不想要一个_id加到你的模式时,你可以使用这个选项禁用它。

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

// 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”模式通过删除空对象。

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。它将存储空的对象。

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 选项在模式层面,为我们提供一种方法来使用默认值 ReadPreferences 为模型的所有查询。

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'。

读选项还允许我们指定标记集。这些告诉 驱动程序 的副本集的成员应该尝试读取。阅读更多关于标签集 这里 这里

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

// 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所有操作并指定如果错误应该回到我们的回调以及调写行为。

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,你也需要把 版本 删掉。在 3.7.x 及以上版本会自动被禁用当安全设置为false。

**注:此设置将覆盖任何设置指定通过传递数据库选项,同时 创建一个连接

还有其他写的问题,如 { w: "majority" } 。看MongoDB 文档 详情。

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

选项: shardKey

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

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

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

选项: strict

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

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() 来设置属性值这样也会起作用。

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

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

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的。

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

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

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方法称为。

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 选项,读

选项: toObject

文档有一个 toObject 的方法将mongoose文档转成成到一个普通的JavaScript对象。此方法接受一些选项。代替这些选项在一个文档的基础上,我们可以声明这里的选项,并将其应用到所有的这个模式文档为默认。

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

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选择,读

选项: typeKey

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

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

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

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。

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 。如果这种与您的应用程序冲突你可以配置:

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禁用。不禁用版本除非你 知道你正在做什么

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扣除路径(例如,内部的修改不会增加即使这些路径更新)。不要这样做,除非你知道你在做什么。对于子文档,使用完全限定的路径将此文件包含在父文档中。

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

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() 只检查顶层模式的严格模式设置。

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会使用子模式的严格选项铸造更新。

var childSchema = new Schema({}, { strict: false });