mongoose
Version:
Mongoose MongoDB ODM
327 lines (292 loc) • 12.9 kB
text/jade
extends layout
block content
h2 Schemas
:markdown
If you haven't yet done so, please take a minute to read the [quickstart](./index.html) to get an idea of how Mongoose works.
:markdown
If you are migrating from 2.x to 3.x please take a moment to read the [migration guide](./migration.html).
:markdown
This page covers `Schema` [definition](#definition), [plugins](#plugins), instance [methods](#methods), [statics](#statics), [indexes](#indexes), [virtuals](#virtuals) and [options](#options). Let's start with `Schema` definition.
h3#definition Defining your schema
p
| Everything in Mongoose starts with a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection.
:js
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
}
})
p
em
| If you want to add additional keys later, use the
a(href="./api.html#schema_Schema-add") Schema#add
| method.
p
| Each key in our
code blogSchema
| defines a property in our documents which will be cast to its associated
a(href="./api.html#schematype_SchemaType") SchemaType
|. Keys may also be assigned nested objects containing further key/type definitions
em (e.g. the `meta` property above).
| For example, we've defined a
code title
| which will be cast to the
a(href="./api.html#schema-string-js") String
| SchemaType and
code date
| which will be cast to a
code Date
| SchemaType.
p
| The permitted SchemaTypes are
ul
li String
li Number
li Date
li Buffer
li Boolean
li Mixed
li ObjectId
li Array
| Read more about them
a(href="./schematypes.html") here
| .
p
| Schemas not only define the structure of your document and casting of properties, they also define document
a(href="#methods") instance methods
|, static
a(href="#statics") Model methods
|,
a(href="#indexes") compound indexes
| and document lifecycle hooks called
a(href="./middleware.html") middleware
|.
h3#plugins Pluggable
p
| Schemas are
a(href="./plugins.html") pluggable
| which allows us to package up reusable features into
a(href="http://plugins.mongoosejs.com") plugins
| that can be shared with the community or just between your projects.
h3#methods Instance methods
p
a(href="./models.html") Models
| are just fancy
code constructor
| functions. As such they can have prototype methods inherited by their instances. In the case of Mongoose, instances are
a(href="./documents.html") documents
|.
p
| Defining an instance method is easy.
:js
var animalSchema = new Schema({ name: String, type: String });
animalSchema.methods.findSimilarTypes = function (cb) {
return this.model('Animal').find({ type: this.type }, cb);
}
p
| Now all of our
code animal
| instances have a
code findSimilarTypes
| method available to it.
:js
var Animal = mongoose.model('Animal', animalSchema);
var dog = new Animal({ type: 'dog' })
dog.findSimilarTypes(function (err, dogs) {
console.log(dogs) // woof
})
h3#statics Statics
p
| Adding static constructor methods to Models is simple as well. Continuing with our
code animalSchema
|:
:js
animalSchema.statics.findByName = function (name, cb) {
this.find({ name: new RegExp(name, 'i'), cb);
}
var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function (err, animals) {
console.log(animals);
})
h3#indexes Indexes
p
a(href="http://www.mongodb.org/display/DOCS/Indexes") Indexes
| can be defined
a(href="./api.html#schematype_SchemaType-index") at
|
a(href="./api.html#schematype_SchemaType-unique") the
|
a(href="./api.html#schematype_SchemaType-sparse") path
|
a(href="./api.html#schematype_SchemaType-expires") level
| or the
code schema
| level. Defining indexes at the schema level is necessary when defining
a(href="http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeys", target="_blank") compound indexes
|.
:js
animalSchema.index({ name: 1, type: -1 });
p
| When your application starts up, Mongoose automatically calls
code ensureIndex
| for each defined index. This behavior can be disabled by setting the
code autoIndex
| option of your schema to false.
:js
animalSchema.set('autoIndex', false)
// or
new Schema({..}, { autoIndex: false })
p
| See also the
a(href="./api.html#model_Model-ensureIndexes")
code Model#ensureIndexes
| method.
h3#virtuals Virtuals
:markdown
[Virtual](./api.html#schema_Schema-virtual) attributes are attributes that are convenient to have around but that do not get persisted to MongoDB.
:js
var personSchema = new Schema({
name: {
first: String,
last: String
}
});
var Person = mongoose.model('Person', personSchema);
var bad = new Person({
name: { first: 'Walter', last: 'White' }
});
:markdown
Suppose we want to log the full name of `bad`. We could do this manually like so:
:js
console.log(bad.name.first + ' ' + bad.name.last); // Walter White
:markdown
Or we could add a `virtual` attribute [getter](./api.html#virtualtype_VirtualType-get) to our `personSchema` so we don't need to write out this string concatenation mess each time:
:js
personSchema.virtual('name.full').get(function () {
return this.name.first + ' ' + this.name.last;
})
:markdown
Now, when we access our virtual full name property, our getter function will be invoked and the value returned:
:js
console.log('%s is insane', bad.name.full) // Walter White is insane
:markdown
It would also be nice to be able to set `this.name.first` and `this.name.last` by setting `this.name.full`. For example, if we wanted to change `bad`'s `name.first` and `name.last` to 'Breaking' and 'Bad' respectively, it'd be nice to just:
:js
bad.name.full = 'Breaking Bad';
:markdown
Mongoose let's you do this as well through its virtual attribute [setters](./api.html#virtualtype_VirtualType-set):
:js
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
:markdown
If you need attributes that you can get and set but that are not themselves persisted to MongoDB, virtual attributes is the Mongoose feature for you.
h3#options Options
:markdown
`Schema`s have a few configurable options which can be passed to the constructor or `set` directly:
:js
new Schema({..}, options);
// or
var schema = new Schema({..});
schema.set(option, value);
:markdown
Valid options:
- [safe](#safe)
- [strict](#strict)
- [capped](#capped)
- [versionKey](#versionKey)
- [autoIndex](#autoIndex)
h4#safe option: safe
:markdown
This option is passed to MongoDB with all operations and let's us specify if errors should be returned to our callbacks as well as tune write behavior.
:js
var safe = true;
new Schema({ .. }, { safe: safe })
:markdown
By default this is set to `true` for all schemas which guarentees that any occurring error gets passed back to our callback.
By setting `safe` to something else like `{ j: 1, w: 2, wtimeout: 10000 }` we can guarantee the write was committed to the MongoDB journal (j: 1), at least 2 replicas (w: 2), and that the write will timeout if it takes longer than 10 seconds (wtimeout: 10000). Errors will still be passed to our callback.
There are other write concerns like `{ w: "majority" }` too. See the MongoDB [docs](http://www.mongodb.org/display/DOCS/getLastError+Command) for more details.
:js
var safe = { w: "majority", wtimeout: 10000 };
new Schema({ .. }, { safe: safe })
h4#strict option: strict
:markdown
The strict option, (enabled by default), ensures that values added to our model instance that were not specified in our schema do not get saved to the db.
_NOTE: do not set to false unless you have good reason._
:js
var thingSchema = new Schema({..})
var Thing = db.model('Thing', schemaSchema);
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!!
:markdown
This value can be overridden at the model instance level by passing a second boolean argument:
:js
var Thing = db.model('Thing');
var thing = new Thing(doc, true); // enables strict mode
var thing = new Thing(doc, false); // disables strict mode
:markdown
The `strict` option may also be set to `"throw"` which will cause errors to be produced instead of ignoring the bad data.
:markdown
_NOTE: in mongoose v2 the default was false._
h4#shardkey option: shardKey
:markdown
The `shardKey` option is used when we have a [sharded MongoDB architecture](http://www.mongodb.org/display/DOCS/Sharding+Introduction). Each sharded collection is given a shard key which must be present in all insert/update operations. We just need to set this schema option to the same shard key and we’ll be all set.
:js
new Schema({ .. }, { shardkey: { tag: 1, name: 1 }})
:markdown
_Note that Mongoose does not send the `shardcollection` command for you. You must configure your shards yourself._
h4#capped option: capped
:markdown
Mongoose supports MongoDBs [capped](http://www.mongodb.org/display/DOCS/Capped+Collections) collections. To specify the underlying MongoDB collection be `capped`, set the `capped` option to the maximum size of the collection in [bytes](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-size.).
:js
new Schema({..}, { capped: 1024 })
:markdown
The `capped` option may also be set to an object if you want to pass additional options like [max](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-max) or [autoIndexId](http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-autoIndexId). In this case you must explicitly pass the `size` option which is required.
:js
new Schema({..}, { capped: { size: 1024, max: 1000, autoIndexId: true })
h4#versionKey option: versionKey
:markdown
The `versionKey` is a property set on each document when first created by Mongoose. This keys value contains the internal [revision](http://aaronheckmann.posterous.com/mongoose-v3-part-1-versioning) of the document. The name of this document property is configurable. The default is `__v`. If this conflicts with your application you can configure as such:
:js
var schema = new Schema({ name: 'string' });
var Thing = db.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 = db.model('Thing', schema);
var thing = new Thing({ name: 'mongoose v3' });
thing.save(); // { _somethingElse: 0, name: 'mongoose v3' }
:markdown
Document versioning can also be disabled by setting the `versionKey` to false. _DO NOT disable versioning unless you [know what you are doing](http://aaronheckmann.posterous.com/mongoose-v3-part-1-versioning)._
:js
new Schema({..}, { versionKey: false })
var Thing = db.model('Thing', schema);
var thing = new Thing({ name: 'no versioning please' });
thing.save(); // { name: 'no versioning please' }
h4#autoIndex option: autoIndex
:markdown
At application startup, Mongoose sends an `ensureIndex` command for each index declared in your `Schema`. As of Mongoose v3, indexes are created in the `background` by default. If you wish to disable the auto-creation feature and manually handle when indexes are created, set your `Schema`s `autoIndex` option to `false` and use the [ensureIndexes](./api.html#model_Model-ensureIndexes) method on your model.
:js
var schema = new Schema({..}, { autoIndex: false })
var Clock = db.model('Clock', schema);
Clock.ensureIndexes(callback);
script.
document.body.className = 'load';
include includes/googleanalytics