- index.js
Mongoose()
Mongoose constructor.
show codefunction Mongoose () { this.connections = []; this.plugins = []; this.models = {}; this.modelSchemas = {}; this.options = {}; this.createConnection(); // default connection };
The exports object of the
mongoose
module is an instance of this class.
Most apps will only use this one instance.Mongoose#set(
key
,value
)Sets mongoose options
show codeMongoose.prototype.set = function (key, value) { if (arguments.length == 1) return this.options[key]; this.options[key] = value; return this; };
Example:
mongoose.set('test', value) // sets the 'test' option to `value`
Mongoose#get(
key
)Gets mongoose options
Parameters:
key
<String>
Example:
mongoose.get('test') // returns the 'test' value
Mongoose#createConnection(
[uri]
)Creates a Connection instance.
show codeMongoose.prototype.createConnection = function () { var conn = new Connection(this); this.connections.push(conn); if (arguments.length) { if (rgxReplSet.test(arguments[0])) { conn.openSet.apply(conn, arguments); } else { conn.open.apply(conn, arguments); } } return conn; };
Parameters:
[uri]
<String> a mongodb:// URI
Returns:
- <Connection> the created Connection object
Example:
// with mongodb:// URI db = mongoose.createConnection('mongodb://localhost:port/database'); // replica sets db = mongoose.createConnection('mongodb://localhost:port/database,mongodb://anotherhost:port,mongodb://yetanother:port'); // with [host, database_name[, port] signature db = mongoose.createConnection('localhost', 'database', port) // initialize now, connect later db = mongoose.createConnection(); db.open('localhost', 'database', port);
Mongoose#connect()
Opens the default mongoose connection.
show codeMongoose.prototype.connect = function () { var conn = this.connection; if (rgxReplSet.test(arguments[0])) { conn.openSet.apply(conn, arguments); } else { conn.open.apply(conn, arguments); } return this; };
Returns:
- <Mongoose> this
If arguments are passed, they are proxied to either Connection#open or Connection#openSet appropriately.
Mongoose#disconnect(
[fn]
)Disconnects all connections.
show codeMongoose.prototype.disconnect = function (fn) { var count = this.connections.length , error this.connections.forEach(function(conn){ conn.close(function(err){ if (error) return; if (err) { error = err; if (fn) return fn(err); throw err; } if (fn) --count || fn(); }); }); return this; };
Parameters:
[fn]
<Function> called after all connection close.
Returns:
- <Mongoose> this
Mongoose#model(
name
,[schema]
,[collection]
,[skipInit]
)Defines a model or retrieves it.
show codeMongoose.prototype.model = function (name, schema, collection, skipInit) { // normalize collection if (!(schema instanceof Schema)) { collection = schema; schema = false; } if ('boolean' === typeof collection) { skipInit = collection; collection = null; } // look up models for the collection if (!this.modelSchemas[name]) { if (!schema && name in SchemaDefaults) { schema = SchemaDefaults[name]; } if (schema) { this.modelSchemas[name] = schema; for (var i = 0, l = this.plugins.length; i < l; i++) { schema.plugin(this.plugins[i][0], this.plugins[i][1]); } } else { throw new Error('Schema hasn\'t been registered for model "' + name + '". ' + 'Use mongoose.model(name, schema)'); } } if (!this.models[name]) { schema || (schema = this.modelSchemas[name]); collection || (collection = schema.set('collection') || format(name)); var model = Model.compile(name , this.modelSchemas[name] , collection , this.connection , this); if (!skipInit) model.init(); this.models[name] = model; } return this.models[name]; };
Parameters:
Models defined on the
mongoose
instance are available to all connection created by the samemongoose
instance.Example:
var mongoose = require('mongoose'); // define an Actor model with this mongoose instance mongoose.model('Actor', new Schema({ name: String })); // create a new connection var conn = mongoose.createConnection(..); // retrieve the Actor model var Actor = conn.model('Actor');
When no
collection
argument is passed, Mongoose produces a collection name by passing the modelname
to the utils.toCollectionName method. This method pluralizes the name. Collection names can also be declared through schema options.Example:
var schema = new Schema({ name: String }); schema.set('collection', 'actor');
Mongoose#plugin(
fn
,[opts]
)Declares a global plugin executed on all Schemas.
show codeMongoose.prototype.plugin = function (fn, opts) { this.plugins.push([fn, opts]); return this; };
Returns:
- <Mongoose> this
Equivalent to calling
.plugin(fn)
on each Schema you create.module.exports
The exports object is an instance of Mongoose.
show codemodule.exports = exports = new Mongoose; var mongoose = module.exports;
mongoose.version
Mongoose version
show codemongoose.version = JSON.parse( require('fs').readFileSync(__dirname + '/../package.json', 'utf8') ).version;
mongoose.Mongoose
The Mongoose constructor
show codemongoose.Mongoose = Mongoose;
The exports of the mongoose module is an instance of this class.
Example:
var mongoose = require('mongoose'); var mongoose2 = new mongoose.Mongoose();
mongoose.Schema
The Mongoose Schema constructor
show codemongoose.Schema = Schema;
Example:
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var CatSchema = new Schema(..);
mongoose.SchemaTypes
The various Mongoose SchemaTypes.
show codemongoose.SchemaTypes = Schema.Types;
Note:
Alias of mongoose.Schema.Types for backwards compatibility.
mongoose.VirtualType
The Mongoose VirtualType constructor.
show codemongoose.VirtualType = VirtualType;
mongoose.Types
The various Mongoose Types.
show codemongoose.Types = Types;
Example:
var mongoose = require('mongoose'); var array = mongoose.Types.Array;
Types:
- Array
- Buffer
- Document
- Embedded
- DocumentArray
- ObjectId
Using this exposed access to the
ObjectId
type, we can construct ids on demand.var ObjectId = mongoose.Types.ObjectId; var id1 = new ObjectId;
mongoose.mongo
The node-mongodb-native driver Mongoose uses.
show codemongoose.mongo = require('mongodb');
Mongoose#connection
The default connection of the mongoose module.
Example:
var mongoose = require('mongoose'); mongoose.connect(...); mongoose.connection.on('error', cb);
This is the connection used by default for every model created using mongoose.model.
Returns:
- collection.js
Collection(
name
,conn
,opts
)Abstract Collection constructor
show codefunction Collection (name, conn, opts) { this.name = name; this.conn = conn; this.buffer = true; this.queue = []; if ('number' == typeof opts) opts = { size: opts }; this.opts = opts || {}; if (STATES.connected == this.conn.readyState) { this.onOpen(); } };
Parameters:
name
<String> name of the collectionconn
<Connection> A MongooseConnection instanceopts
<Object> optional collection options
This is the base class that drivers inherit from and implement.
Collection#onOpen()
Called when the database connects
show codeCollection.prototype.onOpen = function () { var self = this; this.buffer = false; self.doQueue(); };
Collection#onClose()
Called when the database disconnects
show codeCollection.prototype.onClose = function () { this.buffer = true; };
Collection#addQueue(
name
,args
)Queues a method for later execution when its
show code
database connection opens.Collection.prototype.addQueue = function (name, args) { this.queue.push([name, args]); return this; };
Parameters:
Collection#doQueue()
Executes all queued methods and clears the queue.
show codeCollection.prototype.doQueue = function () { for (var i = 0, l = this.queue.length; i < l; i++){ this[this.queue[i][0]].apply(this, this.queue[i][1]); } this.queue = []; return this; };
Collection#ensureIndex()
Abstract method that drivers must implement.
show codeCollection.prototype.ensureIndex = function(){ throw new Error('Collection#ensureIndex unimplemented by driver'); };
Collection#findAndModify()
Abstract method that drivers must implement.
show codeCollection.prototype.findAndModify = function(){ throw new Error('Collection#findAndModify unimplemented by driver'); };
Collection#findOne()
Abstract method that drivers must implement.
show codeCollection.prototype.findOne = function(){ throw new Error('Collection#findOne unimplemented by driver'); };
Collection#find()
Abstract method that drivers must implement.
show codeCollection.prototype.find = function(){ throw new Error('Collection#find unimplemented by driver'); };
Collection#insert()
Abstract method that drivers must implement.
show codeCollection.prototype.insert = function(){ throw new Error('Collection#insert unimplemented by driver'); };
Collection#save()
Abstract method that drivers must implement.
show codeCollection.prototype.save = function(){ throw new Error('Collection#save unimplemented by driver'); };
Collection#update()
Abstract method that drivers must implement.
show codeCollection.prototype.update = function(){ throw new Error('Collection#update unimplemented by driver'); };
Collection#getIndexes()
Abstract method that drivers must implement.
show codeCollection.prototype.getIndexes = function(){ throw new Error('Collection#getIndexes unimplemented by driver'); };
Collection#mapReduce()
Abstract method that drivers must implement.
show codeCollection.prototype.mapReduce = function(){ throw new Error('Collection#mapReduce unimplemented by driver'); };
- connection.js
Connection(
base
)Connection constructor
show codefunction Connection (base) { this.base = base; this.collections = {}; this.models = {}; this.replica = false; this.host = null; this.port = null; this.user = null; this.pass = null; this.name = null; this.options = null; this._readyState = STATES.disconnected; this._closeCalled = false; this._hasOpened = false; };
Parameters:
base
<Mongoose> a mongoose instance
Inherits:
Events:
connecting
: Emitted whenconnection.{open,openSet}()
is executed on this connection.connected
: Emitted when this connection successfully connects to the db. May be emitted multiple times inreconnected
scenarios.open
: Emitted after weconnected
andonOpen
is executed on all of this connections models.disconnecting
: Emitted whenconnection.close()
was executed.disconnected
: Emitted after getting disconnected from the db.close
: Emitted after wedisconnected
andonClose
executed on all of this connections models.reconnected
: Emitted after weconnected
and subsequentlydisconnected
, followed by successfully another successfull connection.error
: Emitted when an error occurs on this connection.fullsetup
: Emitted in a replica-set scenario, when all nodes specified in the connection string are connected.
For practical reasons, a Connection equals a Db.
Connection#open(
connection_string
,[database]
,[port]
,[options]
,[callback]
)Opens the connection to MongoDB.
show codeConnection.prototype.open = function (host, database, port, options, callback) { var self = this , uri; if ('string' === typeof database) { switch (arguments.length) { case 2: port = 27017; case 3: switch (typeof port) { case 'function': callback = port, port = 27017; break; case 'object': options = port, port = 27017; break; } break; case 4: if ('function' === typeof options) callback = options, options = {}; } } else { switch (typeof database) { case 'function': callback = database, database = undefined; break; case 'object': options = database; database = undefined; callback = port; break; } if (!rgxProtocol.test(host)) { host = 'mongodb://' + host; } uri = url.parse(host); host = uri.hostname; port = uri.port || 27017; database = uri.pathname && uri.pathname.replace(/\//g, ''); } this.options = this.defaultOptions(options); // make sure we can open if (STATES.disconnected !== this.readyState) { var err = new Error('Trying to open unclosed connection.'); err.state = this.readyState; this.error(err, callback); return this; } if (!host) { this.error(new Error('Missing connection hostname.'), callback); return this; } if (!database) { this.error(new Error('Missing connection database.'), callback); return this; } // handle authentication if (uri && uri.auth) { var auth = uri.auth.split(':'); this.user = auth[0]; this.pass = auth[1]; // Check hostname for user/pass } else if (/@/.test(host) && /:/.test(host.split('@')[0])) { host = host.split('@'); var auth = host.shift().split(':'); host = host.pop(); this.user = auth[0]; this.pass = auth[1]; // user/pass options } else if (options && options.user && options.pass) { this.user = options.user; this.pass = options.pass; } else { this.user = this.pass = undefined; } this.name = database; this.host = host; this.port = port; this._open(callback); return this; };
Parameters:
options
is a hash with the following possible properties:db - passed to the connection db instance server - passed to the connection server instance(s) replset - passed to the connection ReplSetServer instance user - username for authentication pass - password for authentication
Notes:
Mongoose forces the db option
forceServerObjectId
false and cannot be overridden.
Mongoose defaults the serverauto_reconnect
options to true which can be overridden.
See the node-mongodb-native driver instance for options that it understands.Connection#openSet(
uris
,[database]
,[options]
,[callback]
)Connects to a replica set.
show codeConnection.prototype.openSet = function (uris, database, options, callback) { var uris = uris.split(',') , self = this; switch (arguments.length) { case 3: this.name = database; if ('function' === typeof options) callback = options, options = {}; break; case 2: switch (typeof database) { case 'string': this.name = database; case 'function': callback = database, database = null; break; case 'object': options = database, database = null; break; } } this.options = options = this.defaultOptions(options); if (uris.length < 2) { this.error(new Error('Please provide comma-separated URIs'), callback); return this; } this.replica = true; this.host = []; this.port = []; uris.forEach(function (uri) { // handle missing protocols if (!rgxProtocol.test(uri)) uri = 'mongodb://' + uri; var uri = url.parse(uri); self.host.push(uri.hostname); self.port.push(uri.port || 27017); if (!self.name && uri.pathname && uri.pathname.replace(/\//g, '')) self.name = uri.pathname.replace(/\//g, ''); if (!self.user && uri.auth) { var auth = uri.auth.split(':'); self.user = auth[0]; self.pass = auth[1]; } }); if (!this.name) { this.error(new Error('No database name provided for replica set'), callback); return this; } this._open(callback); return this; };
Parameters:
Example:
var db = mongoose.createConnection(); db.openSet("mongodb://user:pwd@localhost:27020/testing,mongodb://example.com:27020,mongodb://localhost:27019");
The database name and/or auth need only be included in one URI.
Theoptions
are passed to the internal driver connection object.Connection#error(
err
,callback
)error
show codeConnection.prototype.error = function (err, callback) { if (callback) return callback(err); this.emit('error', err); }
Graceful error handling, passes error to callback
if available, else emits error on the connection.Connection#_open(
callback
)Handles opening the connection with the appropriate method based on connection type.
show codeConnection.prototype._open = function (callback) { this.readyState = STATES.connecting; this._closeCalled = false; var self = this; var method = this.replica ? 'doOpenSet' : 'doOpen'; // open connection this[method](function (err) { if (err) { self.readyState = STATES.disconnected; if (self._hasOpened) { if (callback) callback(err); } else { self.error(err, callback); } return; } self.onOpen(); callback && callback(); }); }
Parameters:
callback
<Function>
Connection#onOpen()
Called when the connection is opened
show codeConnection.prototype.onOpen = function () { var self = this; function open () { self.readyState = STATES.connected; // avoid having the collection subscribe to our event emitter // to prevent 0.3 warning for (var i in self.collections) self.collections[i].onOpen(); self.emit('open'); }; // re-authenticate if (self.user && self.pass) self.db.authenticate(self.user, self.pass, open); else open(); };
Connection#close(
[callback]
)Closes the connection
show codeConnection.prototype.close = function (callback) { var self = this; this._closeCalled = true; switch (this.readyState){ case 0: // disconnected callback && callback(); break; case 1: // connected this.readyState = STATES.disconnecting; this.doClose(function(err){ if (err){ self.error(err, callback); } else { self.onClose(); callback && callback(); } }); break; case 2: // connecting this.once('open', function(){ self.close(callback); }); break; case 3: // disconnecting if (!callback) break; this.once('close', function () { callback(); }); break; } return this; };
Parameters:
[callback]
<Function> optional
Returns:
- <Connection> self
Connection#onClose()
Called when the connection closes
show codeConnection.prototype.onClose = function () { this.readyState = STATES.disconnected; // avoid having the collection subscribe to our event emitter // to prevent 0.3 warning for (var i in this.collections) this.collections[i].onClose(); this.emit('close'); };
Connection#collection(
name
,[options]
)Retrieves a collection, creating it if not cached.
show codeConnection.prototype.collection = function (name, options) { if (!(name in this.collections)) this.collections[name] = new Collection(name, this, options); return this.collections[name]; };
Returns:
- <Collection> collection instance
Connection#model(
name
,[schema]
,[collection]
)Defines or retrieves a model.
show codeConnection.prototype.model = function (name, schema, collection) { if (!this.models[name]) { var model = this.base.model(name, schema, collection, true) , Model if (this != model.prototype.db) { // subclass model using this connection and collection name Model = function Model (doc, fields, skipId) { if (!(this instanceof Model)) return new Model(doc, fields, skipId); model.call(this, doc, fields, skipId); }; Model.__proto__ = model; Model.prototype.__proto__ = model.prototype; Model.db = Model.prototype.db = this; // collection name discovery if ('string' === typeof schema) { collection = schema; } if (!collection) { collection = model.prototype.schema.set('collection') || utils.toCollectionName(name); } var s = 'string' != typeof schema ? schema : model.prototype.schema; Model.prototype.collection = this.collection(collection, s && s.options.capped); Model.collection = Model.prototype.collection; Model.init(); } this.models[name] = Model || model; } return this.models[name]; };
Parameters:
Returns:
- <Model> The compiled model
See:
var mongoose = require('mongoose'); var db = mongoose.createConnection(..); db.model('Venue', new Schema(..)); var Ticket = db.model('Ticket', new Schema(..)); var Venue = db.model('Venue');
Connection#setProfiling(
level
,[ms]
,callback
)Set profiling level.
show codeConnection.prototype.setProfiling = function (level, ms, callback) { if (STATES.connected !== this.readyState) { return this.on('open', this.setProfiling.bind(this, level, ms, callback)); } if (!callback) callback = ms, ms = 100; var cmd = {}; switch (level) { case 0: case 'off': cmd.profile = 0; break; case 1: case 'slow': cmd.profile = 1; if ('number' !== typeof ms) { ms = parseInt(ms, 10); if (isNaN(ms)) ms = 100; } cmd.slowms = ms; break; case 2: case 'all': cmd.profile = 2; break; default: return callback(new Error('Invalid profiling level: '+ level)); } this.db.executeDbCommand(cmd, function (err, resp) { if (err) return callback(err); var doc = resp.documents[0]; err = 1 === doc.ok ? null : new Error('Could not set profiling level to: '+ level) callback(err, doc); }); };
Parameters:
Connection#defaultOptions(
options
)Prepares default connection options.
show codeConnection.prototype.defaultOptions = function (options) { var o = options || {}; o.server = o.server || {}; if (!('auto_reconnect' in o.server)) { o.server.auto_reconnect = true; } o.db = o.db || {}; o.db.forceServerObjectId = false; return o; }
Parameters:
options
<Object>
Connection#readyState
Connection ready state
- 0 = disconnected
- 1 = connected
- 2 = connecting
- 3 = disconnecting
Each state change emits its associated event name.
Example
conn.on('connected', callback); conn.on('disconnected', callback);
- document.js
Document(
obj
,[fields]
,[skipId]
)Document constructor.
show codefunction Document (obj, fields, skipId) { // node <0.4.3 bug if (!this._events) this._events = {}; this.setMaxListeners(0); if ('boolean' === typeof fields) { this._strictMode = fields; this._selected = fields = undefined; } else { this._strictMode = this.schema.options && this.schema.options.strict; this._selected = fields; } this.isNew = true; this.errors = undefined; this._shardval = undefined; this._saveError = undefined; this._validationError = undefined; this._adhocPaths = undefined; this._removing = undefined; this._inserting = undefined; this.__version = undefined; this.__getters = {}; this.__id = undefined; this._activePaths = new ActiveRoster; var required = this.schema.requiredPaths(); for (var i = 0; i < required.length; ++i) { this._activePaths.require(required[i]); } this._doc = this._buildDoc(obj, fields, skipId); if (obj) this.set(obj, undefined, true); this._registerHooks(); };
Parameters:
Inherits:
Events:
init
: Emitted on a document after it has was retreived from the db and fully hydrated by Mongoose.save
: Emitted when the document is successfully saved
Document#_buildDoc(
obj
,[fields]
,[skipId]
)Builds the default doc structure
show codeDocument.prototype._buildDoc = function (obj, fields, skipId) { var doc = {} , self = this , exclude , keys , key , ki // determine if this doc is a result of a query with // excluded fields if (fields && 'Object' === fields.constructor.name) { keys = Object.keys(fields); ki = keys.length; while (ki--) { if ('_id' !== keys[ki]) { exclude = 0 === fields[keys[ki]]; break; } } } var paths = Object.keys(this.schema.paths) , plen = paths.length , ii = 0 for (; ii < plen; ++ii) { var p = paths[ii]; if ('_id' == p) { if (skipId) continue; if (obj && '_id' in obj) continue; } var type = this.schema.paths[p] , path = p.split('.') , len = path.length , last = len-1 , doc_ = doc , i = 0 for (; i < len; ++i) { var piece = path[i] , def if (i === last) { if (fields) { if (exclude) { // apply defaults to all non-excluded fields if (p in fields) continue; def = type.getDefault(self, true); if ('undefined' !== typeof def) { doc_[piece] = def; self._activePaths.default(p); } } else if (p in fields) { // selected field def = type.getDefault(self, true); if ('undefined' !== typeof def) { doc_[piece] = def; self._activePaths.default(p); } } } else { def = type.getDefault(self, true); if ('undefined' !== typeof def) { doc_[piece] = def; self._activePaths.default(p); } } } else { doc_ = doc_[piece] || (doc_[piece] = {}); } } }; return doc; };
Returns:
- <Object>
Document#init(
doc
,fn
)Initializes the document without setters or marking anything modified.
show codeDocument.prototype.init = function (doc, fn) { this.isNew = false; init(this, doc, this._doc); this._storeShard(); this.emit('init'); if (fn) fn(null); return this; };
Called internally after a document is returned from mongodb.
Document#_storeShard()
Stores the current values of the shard keys.
show codeDocument.prototype._storeShard = function _storeShard () { // backwards compat var key = this.schema.options.shardKey || this.schema.options.shardkey; if (!(key && 'Object' == key.constructor.name)) return; var orig = this._shardval = {} , paths = Object.keys(key) , len = paths.length , val for (var i = 0; i < len; ++i) { val = this.getValue(paths[i]); if (isMongooseObject(val)) { orig[paths[i]] = val.toObject({ depopulate: true }) } else if (null != val && val.valueOf) { orig[paths[i]] = val.valueOf(); } else { orig[paths[i]] = val; } } }
Note:
Shard key values do not / are not allowed to change.
Document#update(
doc
,options
,callback
)Sends an update command with this document
show code_id
as the query selector.Document.prototype.update = function update () { var args = utils.args(arguments); args.unshift({_id: this._id}); this.constructor.update.apply(this.constructor, args); }
Returns:
- <Query>
Example:
weirdCar.update({$inc: {wheels:1}}, { safe: true }, callback);
Valid options:
safe
safe mode (defaults to value set in schema (true))upsert
(boolean) whether to create the doc if it doesn't match (false)
Document#set(
path
,val
,[type]
)Sets the value of a path, or many paths.
show codeDocument.prototype.set = function (path, val, type) { var constructing = true === type , adhoc = type && true !== type , adhocs if (adhoc) { adhocs = this._adhocPaths || (this._adhocPaths = {}); adhocs[path] = Schema.interpretAsType(path, type); } if ('string' !== typeof path) { // new Document({ key: val }) if (null === path || undefined === path) { var _ = path; path = val; val = _; } else { var prefix = val ? val + '.' : ''; if (path instanceof Document) path = path._doc; var keys = Object.keys(path) , i = keys.length , pathtype , key while (i--) { key = keys[i]; if (null != path[key] && 'Object' === path[key].constructor.name && !(this._path(prefix + key) instanceof MixedSchema)) { this.set(path[key], prefix + key, constructing); } else if (this._strictMode) { pathtype = this.schema.pathType(prefix + key); if ('real' === pathtype || 'virtual' === pathtype) { this.set(prefix + key, path[key], constructing); } else if ('throw' == this._strictMode) { throw new Error("Field `" + key + "` is not in schema."); } } else if (undefined !== path[key]) { this.set(prefix + key, path[key], constructing); } } return this; } } // ensure _strict is honored for obj props // docschema = new Schema({ path: { nest: 'string' }}) // doc.set('path', obj); var pathType = this.schema.pathType(path); if ('nested' == pathType && val && 'Object' == val.constructor.name) { this.set(val, path, constructing); return this; } var schema; if ('adhocOrUndefined' == pathType && this._strictMode) { return this; } else if ('virtual' == pathType) { schema = this.schema.virtualpath(path); schema.applySetters(val, this); return this; } else { schema = this._path(path); } var parts = path.split('.') , pathToMark // When using the $set operator the path to the field must already exist. // Else mongodb throws: "LEFT_SUBFIELD only supports Object" if (parts.length <= 1) { pathToMark = path; } else { for (var i = 0; i < parts.length; ++i) { var part = parts[i]; var subpath = parts.slice(0, i).concat(part).join('.'); if (this.isDirectModified(subpath) // earlier prefixes that are already // marked as dirty have precedence || this.get(subpath) === null) { pathToMark = subpath; break; } } if (!pathToMark) pathToMark = path; } if (!schema || null === val || undefined === val) { this._set(pathToMark, path, constructing, parts, schema, val); return this; } var self = this; // if this doc is being constructed we should not // trigger getters. var priorVal = constructing ? undefined : this.get(path); var shouldSet = this.try(function(){ val = schema.applySetters(val, self, false, priorVal); }); if (shouldSet) { this._set(pathToMark, path, constructing, parts, schema, val, priorVal); } return this; }
Parameters:
Example:
// path, value doc.set(path, value) // object doc.set({ path : value , path2 : { path : value } }) // only-the-fly cast to number doc.set(path, value, Number) // only-the-fly cast to string doc.set(path, value, String)
Document#_set()
Handles the actual setting of the value and marking the path modified if appropriate.
show codeDocument.prototype._set = function (pathToMark, path, constructing, parts, schema, val, priorVal) { if (this.isNew) { this.markModified(pathToMark); } else { priorVal || (priorVal = this.get(path)); if (!this.isDirectModified(pathToMark)) { if (undefined === val && !this.isSelected(path)) { // special case: // when a path is not selected in a query its initial // value will be undefined. this.markModified(pathToMark, priorVal); } else if (undefined === val && path in this._activePaths.states.default) { // do nothing // unsetting the default value which was never saved } else if (!deepEqual(val, priorVal)) { this.markModified(pathToMark, priorVal); } else if (!constructing && null != val && path in this._activePaths.states.default && deepEqual(val, schema.getDefault(this, constructing))) { // special case: // a path with a default was $unset on the server // and the user is setting it to the same value again this.markModified(pathToMark, priorVal); } } } var obj = this._doc , i = 0 , l = parts.length for (; i < l; i++) { var next = i + 1 , last = next === l; if (last) { obj[parts[i]] = val; } else { if (obj[parts[i]] && 'Object' === obj[parts[i]].constructor.name) { obj = obj[parts[i]]; } else if (obj[parts[i]] && Array.isArray(obj[parts[i]])) { obj = obj[parts[i]]; } else { obj = obj[parts[i]] = {}; } } } };
Document#getValue(
path
)Gets a raw value from a path (no getters)
show codeDocument.prototype.getValue = function (path) { var parts = path.split('.') , obj = this._doc , part; for (var i = 0, l = parts.length; i < l; i++) { part = parts[i]; obj = obj.getValue ? obj.getValue(part) // If we have an embedded array document member : obj[part]; if (!obj) return obj; } return obj; }
Parameters:
path
<String>
Document#setValue(
path
,value
)Sets a raw value for a path (no casting, setters, transformations)
show codeDocument.prototype.setValue = function (path, val) { var parts = path.split('.') , obj = this._doc; for (var i = 0, len = parts.length-1; i < len; i++) { obj = obj[parts[i]]; } obj[parts[len]] = val; return this; };
Document#get(
path
,[type]
)Returns the value of a path.
show codeDocument.prototype.get = function (path, type) { var adhocs; if (type) { adhocs = this._adhocPaths || (this._adhocPaths = {}); adhocs[path] = Schema.interpretAsType(path, type); } var schema = this._path(path) || this.schema.virtualpath(path) , pieces = path.split('.') , obj = this._doc; for (var i = 0, l = pieces.length; i < l; i++) { obj = null == obj ? null : obj[pieces[i]]; } if (schema) { obj = schema.applyGetters(obj, this); } return obj; };
Parameters:
Example
// path doc.get('age') // 47 // dynamic casting to a string doc.get('age', String) // "47"
Document#_path(
path
)Returns the schematype for the given
show codepath
.Document.prototype._path = function (path) { var adhocs = this._adhocPaths , adhocType = adhocs && adhocs[path]; if (adhocType) { return adhocType; } else { return this.schema.path(path); } };
Parameters:
path
<String>
Document#markModified(
path
)Marks the path as having pending changes to write to the db.
show codeDocument.prototype.markModified = function (path) { this._activePaths.modify(path); };
Parameters:
path
<String> the path to mark modified
Very helpful when using Mixed types.
Example:
doc.mixed.type = 'changed'; doc.markModified('mixed.type'); doc.save() // changes to mixed.type are now persisted
Document#try(
fn
,scope
)Catches errors that occur during execution of
show codefn
and stores them to later be passed whensave()
is executed.Document.prototype.try = function (fn, scope) { var res; try { fn.call(scope); res = true; } catch (e) { this._error(e); res = false; } return res; };
Document#modifiedPaths()
Returns the list of paths that have been modified.
show codeDocument.prototype.modifiedPaths = function () { var directModifiedPaths = Object.keys(this._activePaths.states.modify); return directModifiedPaths.reduce(function (list, path) { var parts = path.split('.'); return list.concat(parts.reduce(function (chains, part, i) { return chains.concat(parts.slice(0, i).concat(part).join('.')); }, [])); }, []); };
Returns:
- <Array>
Document#isModified(
[path]
)Returns true if this document was modified, else false.
show codeDocument.prototype.isModified = function (path) { return path ? !!~this.modifiedPaths().indexOf(path) : this._activePaths.some('modify'); };
Parameters:
[path]
<String> optional
Returns:
- <Boolean>
If
path
is given, checks if a path or any full path containingpath
as part of its path chain has been modified.Example
doc.set('documents.0.title', 'changed'); doc.isModified() // true doc.isModified('documents') // true doc.isModified('documents.0.title') // true doc.isDirectModified('documents') // false
Document#isDirectModified(
path
)Returns true if
show codepath
was directly set and modified, else false.Document.prototype.isDirectModified = function (path) { return (path in this._activePaths.states.modify); };
Parameters:
path
<String>
Returns:
- <Boolean>
Example
doc.set('documents.0.title', 'changed'); doc.isDirectModified('documents.0.title') // true doc.isDirectModified('documents') // false
Document#isInit(
path
)Checks if
show codepath
was initialized.Document.prototype.isInit = function (path) { return (path in this._activePaths.states.init); };
Parameters:
path
<String>
Returns:
- <Boolean>
Document#isSelected(
path
)Checks if
show codepath
was selected in the source query which initialized this document.Document.prototype.isSelected = function isSelected (path) { if (this._selected) { if ('_id' === path) { return 0 !== this._selected._id; } var paths = Object.keys(this._selected) , i = paths.length , inclusive = false , cur if (1 === i && '_id' === paths[0]) { // only _id was selected. return 0 === this._selected._id; } while (i--) { cur = paths[i]; if ('_id' == cur) continue; inclusive = !! this._selected[cur]; break; } if (path in this._selected) { return inclusive; } i = paths.length; var pathDot = path + '.'; while (i--) { cur = paths[i]; if ('_id' == cur) continue; if (0 === cur.indexOf(pathDot)) { return inclusive; } if (0 === pathDot.indexOf(cur)) { return inclusive; } } return ! inclusive; } return true; }
Parameters:
path
<String>
Returns:
- <Boolean>
Example
Thing.findOne().select('name').exec(function (err, doc) { doc.isSelected('name') // true doc.isSelected('age') // false })
Document#validate(
cb
)Executes registered validation rules for this document.
show codeDocument.prototype.validate = function (cb) { var self = this // only validate required fields when necessary var paths = Object.keys(this._activePaths.states.require).filter(function (path) { if (!self.isSelected(path) && !self.isModified(path)) return false; return true; }); paths = paths.concat(Object.keys(this._activePaths.states.init)); paths = paths.concat(Object.keys(this._activePaths.states.modify)); if (0 === paths.length) { complete(); return this; } var validating = {} , total = 0; paths.forEach(validatePath); return this; function validatePath (path) { if (validating[path]) return; validating[path] = true; total++; process.nextTick(function(){ var p = self.schema.path(path); if (!p) return --total || complete(); p.doValidate(self.getValue(path), function (err) { if (err) self.invalidate(path, err, true); --total || complete(); }, self); }); } function complete () { var err = self._validationError; self._validationError = undefined; cb(err); } };
Parameters:
cb
<Function> called after validation completes, passing an error if one occurred
Note:
This method is called
pre
save and if a validation rule is violated, save is aborted and the error is returned to yourcallback
.Example:
doc.validate(function (err) { if (err) handleError(err); else // validation passed });
Document#invalidate(
path
,err
)Marks a path as invalid, causing validation to fail.
show codeDocument.prototype.invalidate = function (path, err) { if (!this._validationError) { this._validationError = new ValidationError(this); } if (!err || 'string' === typeof err) { err = new ValidatorError(path, err); } this._validationError.errors[path] = err; }
Parameters:
Document#_reset()
Resets the internal modified state of this document.
show codeDocument.prototype._reset = function reset () { var self = this; DocumentArray || (DocumentArray = require('./types/documentarray')); this._activePaths .map('init', 'modify', function (i) { return self.getValue(i); }) .filter(function (val) { return (val && val instanceof DocumentArray && val.length); }) .forEach(function (array) { array.forEach(function (doc) { doc._reset(); }); }); // clear atomics this._dirty().forEach(function (dirt) { var type = dirt.value; if (type && type._atomics) { type._atomics = {}; } }); // Clear 'modify'('dirty') cache this._activePaths.clear('modify'); this._validationError = undefined; this.errors = undefined; var self = this; this.schema.requiredPaths().forEach(function (path) { self._activePaths.require(path); }); return this; }
Returns:
- <Document>
Document#_dirty()
Returns this documents dirty paths / vals.
show codeDocument.prototype._dirty = function _dirty () { var self = this; var all = this._activePaths.map('modify', function (path) { return { path: path , value: self.getValue(path) , schema: self._path(path) }; }); // Sort dirty paths in a flat hierarchy. all.sort(function (a, b) { return (a.path < b.path ? -1 : (a.path > b.path ? 1 : 0)); }); // Ignore "foo.a" if "foo" is dirty already. var minimal = [] , lastPath , top; all.forEach(function (item, i) { if (item.path.indexOf(lastPath) !== 0) { lastPath = item.path + '.'; minimal.push(item); top = item; } else { if (!(item.value && top.value)) return; // special case for top level MongooseArrays if (top.value._atomics && top.value.hasAtomics()) { // the `top` array itself and a sub path of `top` are being modified. // the only way to honor all of both modifications is through a $set // of entire array. top.value._atomics = {}; top.value._atomics.$set = top.value; } } }); top = lastPath = null; return minimal; }
Document#_setSchema(
schema
)Assigns/compiles
show codeschema
into this documents prototype.Document.prototype._setSchema = function (schema) { compile(schema.tree, this); this.schema = schema; }
Parameters:
schema
<Schema>
Document#_registerHooks()
Register default hooks
show codeDocument.prototype._registerHooks = function _registerHooks () { if (!this.save) return; DocumentArray || (DocumentArray = require('./types/documentarray')); this.pre('save', function (next) { // we keep the error semaphore to make sure we don't // call `save` unnecessarily (we only need 1 error) var subdocs = 0 , error = false , self = this; // check for DocumentArrays var arrays = this._activePaths .map('init', 'modify', function (i) { return self.getValue(i); }) .filter(function (val) { return (val && val instanceof DocumentArray && val.length); }); if (!arrays.length) return next(); arrays.forEach(function (array) { subdocs += array.length; array.forEach(function (value) { if (error) return; value.save(function (err) { if (error) return; if (err) { error = true; self._validationError = undefined; return next(err); } --subdocs || next(); }); }); }); }, function (err) { // emit on the Model if listening if (this.constructor.listeners('error').length) { this.constructor.emit('error', err); } else { // emit on the connection if (!this.db.listeners('error').length) { err.stack = 'No listeners detected, throwing. ' + 'Consider adding an error listener to your connection. ' + err.stack } this.db.emit('error', err); } }).pre('save', function checkForExistingErrors (next) { // if any doc.set() calls failed if (this._saveError) { next(this._saveError); this._saveError = null; } else { next(); } }).pre('save', function validation (next) { return this.validate(next); }); // add user defined queues this._doQueue(); };
Document#_error(
err
)Registers an error
show codeDocument.prototype._error = function (err) { this._saveError = err; return this; };
Parameters:
err
<Error>
Document#_doQueue()
Executes methods queued from the Schema definition
show codeDocument.prototype._doQueue = function () { var q = this.schema && this.schema.callQueue; if (q) { for (var i = 0, l = q.length; i < l; i++) { this[q[i][0]].apply(this, q[i][1]); } } return this; };
Document#toObject(
[options]
)Converts this document into a plain javascript object
show codeDocument.prototype.toObject = function (options) { // When internally saving this document we always pass options, // bypassing the custom schema options. if (!(options && 'Object' == options.constructor.name)) { options = this.schema.options.toObject ? clone(this.schema.options.toObject) : {}; } ;('minimize' in options) || (options.minimize = this.schema.options.minimize); var ret = clone(this._doc, options); if (options.virtuals || options.getters && false !== options.virtuals) { applyGetters(this, ret, 'virtuals', options); } if (options.getters) { applyGetters(this, ret, 'paths', options); } return ret; };
Parameters:
[options]
<Object>
Returns:
- <Object> js object
Options:
getters
apply all getters (path and virtual getters)virtuals
apply virtual getters (can overridegetters
option)minimize
remove empty objects (defaults to true)
Example of only applying path getters
doc.toObject({ getters: true, virtuals: false })
Example of only applying virtual getters
doc.toObject({ virtuals: true })
Example of applying both path and virtual getters
doc.toObject({ getters: true })
Document#toJSON(
options
)The return value of this method is used in calls to JSON.stringify(doc).
show codeDocument.prototype.toJSON = function (options) { // check for object type since an array of documents // being stringified passes array indexes instead // of options objects. JSON.stringify([doc, doc]) if (!(options && 'Object' == options.constructor.name)) { options = this.schema.options.toJSON ? clone(this.schema.options.toJSON) : {}; } options.json = true; return this.toObject(options); };
Parameters:
options
<Object> same options as Document#toObject
Returns:
- <Object>
Document#inspect()
Helper for console.log
show codeDocument.prototype.inspect = function (options) { var opts = options && 'Object' == options.constructor.name ? options : undefined return inspect(this.toObject(opts)); };
Document#equals(
doc
)Returns true if the Document stores the same data as doc.
show codeDocument.prototype.equals = function (doc) { var tid = this.get('_id'); var docid = doc.get('_id'); return tid.equals ? tid.equals(docid) : tid === docid; };
Parameters:
doc
<Document> a document to compare
Returns:
- <Boolean>
Documents are considered equal when they have matching
_id
s.Document#id
The string version of this documents _id.
Note:
This getter exists on all documents by default. The getter can be disabled by setting the
id
option of itsSchema
to false at construction time.new Schema({ name: String }, { id: false });
- drivers/node-mongodb-native/collection.js
NativeCollection()
A node-mongodb-native collection implementation.
show codefunction NativeCollection () { this.collection = null; MongooseCollection.apply(this, arguments); }
Inherits:
All methods methods from the node-mongodb-native driver are copied and wrapped in queue management.
NativeCollection#onOpen()
Called when the connection opens.
show codeNativeCollection.prototype.onOpen = function () { var self = this; if (this.collection) { return MongooseCollection.prototype.onOpen.call(self); } if (!self.opts.size) { // non-capped return self.conn.db.collection(self.name, callback); } // capped return self.conn.db.collection(self.name, function (err, c) { if (err) return callback(err); // discover if this collection exists and if it is capped c.options(function (err, exists) { if (err) return callback(err); if (exists) { if (exists.capped) { callback(null, c); } else { var msg = 'A non-capped collection exists with this name. ' + ' To use this collection as a capped collection, please ' + 'first convert it. ' + ' http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-Convertingacollectiontocapped' err = new Error(msg); callback(err); } } else { // create var opts = utils.clone(self.opts); opts.capped = true; self.conn.db.createCollection(self.name, opts, callback); } }); }); function callback (err, collection) { if (err) { // likely a strict mode error self.conn.emit('error', err); } else { self.collection = collection; MongooseCollection.prototype.onOpen.call(self); } }; };
NativeCollection#onClose()
Called when the connection closes
show codeNativeCollection.prototype.onClose = function () { MongooseCollection.prototype.onClose.call(this); };
NativeCollection#getIndexes(
callback
)Retreives information about this collections indexes.
Parameters:
callback
<Function>
- drivers/node-mongodb-native/connection.js
NativeConnection()
A node-mongodb-native connection implementation.
show codefunction NativeConnection() { MongooseConnection.apply(this, arguments); };
Inherits:
NativeConnection#doOpen(
fn
)Opens the connection to MongoDB.
show codeNativeConnection.prototype.doOpen = function (fn) { var server , self = this; if (!this.db) { server = new mongo.Server(this.host, Number(this.port), this.options.server); this.db = new mongo.Db(this.name, server, this.options.db); } this.db.open(function (err) { if (err) return fn(err); fn(); listen(self); }); return this; }; function listen (conn) { if (conn._listening) return; conn._listening = true; conn.db.on('close', function(){ if (conn._closeCalled) return; // the driver never emits an `open` event. auto_reconnect still // emits a `close` event but since we never get another // `open` we can't emit close if (conn.db.serverConfig.autoReconnect) { conn.readyState = STATES.disconnected; conn.emit('close'); return; } conn.onClose(); }); conn.db.on('error', function(err){ conn.emit('error', err); }); conn.db.on('timeout', function(err){ var error = new Error(err && err.err || 'connection timeout'); conn.emit('error', error); }); conn.db.on('open', function (err, db) { if (STATES.disconnected === conn.readyState && db && db.databaseName) { conn.readyState = STATES.connected; conn.emit('reconnected') } }) }
Parameters:
fn
<Function>
Returns:
- <Connection> this
NativeConnection#doOpenSet(
fn
)Opens a connection to a MongoDB ReplicaSet.
show codeNativeConnection.prototype.doOpenSet = function (fn) { if (!this.db) { var servers = [] , ports = this.port , self = this this.host.forEach(function (host, i) { servers.push(new mongo.Server(host, Number(ports[i]), self.options.server)); }); var server = new ReplSetServers(servers, this.options.replset); this.db = new mongo.Db(this.name, server, this.options.db); this.db.on('fullsetup', function () { self.emit('fullsetup') }); } this.db.open(function (err) { if (err) return fn(err); fn(); listen(self); }); return this; };
Parameters:
fn
<Function>
Returns:
- <Connection> this
See description of doOpen for server options. In this case
options.replset
is also passed to ReplSetServers.NativeConnection#doClose(
fn
)Closes the connection
show codeNativeConnection.prototype.doClose = function (fn) { this.db.close(); if (fn) fn(); return this; }
Parameters:
fn
<Function>
Returns:
- <Connection> this
- error.js
MongooseError()
Mongoose error
show codefunction MongooseError (msg) { Error.call(this); Error.captureStackTrace(this, arguments.callee); this.message = msg; this.name = 'MongooseError'; };
Inherits:
- errors/cast.js
CastError(
type
,value
)Casting Error constructor.
show codefunction CastError (type, value) { MongooseError.call(this, 'Cast to ' + type + ' failed for value "' + value + '"'); Error.captureStackTrace(this, arguments.callee); this.name = 'CastError'; this.type = type; this.value = value; };
Inherits:
- errors/document.js
DocumentError(
msg
)Document Error
show codefunction DocumentError (msg) { MongooseError.call(this, msg); Error.captureStackTrace(this, arguments.callee); this.name = 'DocumentError'; };
Parameters:
msg
<String>
Inherits:
- errors/validation.js
ValidationError(
instance
)Document Validation Error
show codefunction ValidationError (instance) { MongooseError.call(this, "Validation failed"); Error.captureStackTrace(this, arguments.callee); this.name = 'ValidationError'; this.errors = instance.errors = {}; };
Parameters:
instance
<Document>
Inherits:
ValidationError#toString()
Console.log helper
show codeValidationError.prototype.toString = function () { return this.name + ': ' + Object.keys(this.errors).map(function (key) { return String(this.errors[key]); }, this).join(', '); };
- errors/validator.js
ValidatorError(
path
,msg
)Schema validator error
show codefunction ValidatorError (path, type) { var msg = type ? '"' + type + '" ' : ''; MongooseError.call(this, 'Validator ' + msg + 'failed for path ' + path); Error.captureStackTrace(this, arguments.callee); this.name = 'ValidatorError'; this.path = path; this.type = type; };
Inherits:
- model.js
Model(
doc
)Model constructor
show codefunction Model (doc, fields, skipId) { Document.call(this, doc, fields, skipId); };
Parameters:
doc
<Object> values to with which to create the document
Inherits:
Events:
error
: If listening to this Model event, it is emitted when a document was saved without passing a callback and anerror
occurred. If not listening, the event bubbles to the connection used to create this Model.index
: Emitted afterModel#ensureIndexes
completes. If an error occurred it is passed with the event.
Model#_getPopulationKeys(
query
)Returns what paths can be populated
show codeModel.prototype._getPopulationKeys = function getPopulationKeys (query) { if (!(query && query.options.populate)) return; var names = Object.keys(query.options.populate) , n = names.length , name , paths = {} , hasKeys , schema while (n--) { name = names[n]; schema = this.schema.path(name); hasKeys = true; if (!schema) { // if the path is not recognized, it's potentially embedded docs // walk path atoms from right to left to find a matching path var pieces = name.split('.') , i = pieces.length; while (i--) { var path = pieces.slice(0, i).join('.') , pathSchema = this.schema.path(path); // loop until we find an array schema if (pathSchema && pathSchema.caster) { if (!paths[path]) { paths[path] = { sub: {} }; } paths[path].sub[pieces.slice(i).join('.')] = query.options.populate[name]; hasKeys || (hasKeys = true); break; } } } else { paths[name] = query.options.populate[name]; hasKeys || (hasKeys = true); } } return hasKeys && paths; };
Parameters:
query
<Query> object
Model#_populate(
schema
,oid
,query
,fn
)Populates an object
show codeModel.prototype._populate = function populate (schema, oid, query, fn) { if (!Array.isArray(oid)) { var conditions = query.conditions || {}; conditions._id = oid; return this .db.model(query.model || schema.options.ref) .findOne(conditions, query.fields, query.options, fn); } if (!oid.length) { return fn(null, oid); } var model = this.db.model(query.model || schema.caster.options.ref) , conditions = query && query.conditions || {}; conditions._id || (conditions._id = { $in: oid }); model.find(conditions, query.fields, query.options, function (err, docs) { if (err) return fn(err); // user specified sort order? if (query.options && query.options.sort) { return fn(null, docs); } // put back in original id order (using a hash reduces complexity from n*n to 2n) var docHash = {}; docs.forEach(function (doc) { docHash[doc._id] = doc; }); var arr = []; oid.forEach(function (id) { if (id in docHash) arr.push(docHash[id]); }); fn(null, arr); }); };
Parameters:
schema
<SchemaType> type for the oidoid
<Object> object id or array of object idsquery
<Object> object specifying query conditions, fields, and optionsfn
<Function>
Model#init(
doc
,query
,fn
)Performs auto-population of relations.
show codeModel.prototype.init = function init (doc, query, fn) { if ('function' == typeof query) { fn = query; query = null; } var populate = this._getPopulationKeys(query); if (!populate) { return Document.prototype.init.call(this, doc, fn); } // population from other models is necessary var self = this; init(doc, '', function (err) { if (err) return fn(err); Document.prototype.init.call(self, doc, fn); }); return this; function init (obj, prefix, fn) { prefix = prefix || ''; var keys = Object.keys(obj) , len = keys.length; return next(); function next () { if (--len < 0) return fn(); var i = keys[len] , path = prefix + i , schema = self.schema.path(path) , total = 0 , inline = false , poppath if (!schema && obj[i] && 'Object' === obj[i].constructor.name) { // assume nested object return init(obj[i], path + '.', next); } if (!(obj[i] && schema && populate[path])) return next(); // this query object is re-used and passed around. we clone // it to prevent query condition contamination between // one populate call to the next. poppath = utils.clone(populate[path]); if (poppath.sub) { obj[i].forEach(function (subobj) { inline = true; var pkeys = Object.keys(poppath.sub) , pi = pkeys.length , key while (pi--) { key = pkeys[pi]; if (subobj[key]) (function (key) { total++; self._populate(schema.schema.path(key), subobj[key], poppath.sub[key], done); function done (err, doc) { if (err) return error(err); subobj[key] = doc; if (--total < 1 && !inline) { next(); } } })(key); } }); inline = false; if (0 === total) return next(); } else { self._populate(schema, obj[i], poppath, function (err, doc) { if (err) return error(err); obj[i] = doc; next(); }); } }; }; function error (err) { if (error.err) return; fn(error.err = err); } };
Parameters:
Model#save(
[fn]
)Saves this document.
show codeModel.prototype.save = function save (fn) { var promise = new Promise(fn) , complete = handleSave(promise, this) , options = {} if (this.schema.options.safe) { options.safe = this.schema.options.safe; } if (this.isNew) { // send entire doc var obj = this.toObject({ depopulate: 1 }); this._version(true, obj); this.collection.insert(obj, options, complete); this._reset(); this.isNew = false; this.emit('isNew', false); // Make it possible to retry the insert this._inserting = true; } else { // Make sure we don't treat it as a new object on error, // since it already exists this._inserting = false; var delta = this._delta(); if (delta) { var where = this._where(delta[0]); this.collection.update(where, delta[1], options, complete); } else { complete(null); } this._reset(); this.emit('isNew', false); } };
Parameters:
[fn]
<Function> optional callback
See:
Example:
product.sold = Date.now(); product.save(function (err, product) { if (err) .. })
The
fn
callback is optional. If nofn
is passed and validation fails, the validation error will be emitted on the connection used to create this model.var db = mongoose.createConnection(..); var schema = new Schema(..); var Product = db.model('Product', schema); db.on('error', handleError);
However, if you desire more local error handling you can add an
error
listener to the model and handle errors there instead.Product.on('error', handleError);
Model#_delta()
Produces a special query document of the modified properties used in updates.
show codeModel.prototype._delta = function _delta () { var dirty = this._dirty(); if (!dirty.length) return; var self = this , where = {} , delta = {} , len = dirty.length , d = 0 , val , obj for (; d < len; ++d) { var data = dirty[d] var value = data.value var schema = data.schema if (undefined === value) { operand(self, where, delta, data, 1, '$unset'); } else if (null === value) { operand(self, where, delta, data, null); } else if (value._path && value._atomics) { handleAtomics(self, where, delta, data, value); } else if (value._path && Buffer.isBuffer(value)) { // MongooseBuffer value = value.toObject(); operand(self, where, delta, data, value); } else { value = utils.clone(value); operand(self, where, delta, data, value); } } if (this.__version) { this._version(where, delta); } return [where, delta]; }
Model#_version()
Appends versioning to the where and update clauses.
show codeModel.prototype._version = function _version (where, delta) { var key = this.schema.options.versionKey; if (true === where) { // this is an insert if (key) this.setValue(key, delta[key] = 0); return; } // updates // only apply versioning if our versionKey was selected. else // there is no way to select the correct version. we could fail // fast here and force them to include the versionKey but // thats a bit intrusive. can we do this automatically? // TODO fail fast option? if (!this.isSelected(key)) { return; } // $push $addToSet don't need the where clause set if (VERSION_WHERE === (VERSION_WHERE & this.__version)) { where[key] = this.getValue(key); } if (VERSION_INC === (VERSION_INC & this.__version)) { delta.$inc || (delta.$inc = {}); delta.$inc[key] = 1; } }
Model#increment()
Signal that we desire an increment of this documents version.
show codeModel.prototype.increment = function increment () { this.__version = VERSION_ALL; return this; }
See:
Model#_where()
Returns a query object which applies shardkeys if they exist.
show codeModel.prototype._where = function _where (where) { where || (where = {}); var paths , len if (this._shardval) { paths = Object.keys(this._shardval) len = paths.length for (var i = 0; i < len; ++i) { where[paths[i]] = this._shardval[paths[i]]; } } where._id = this._doc._id; return where; }
Model#remove(
[fn]
)Removes this document from the db.
show codeModel.prototype.remove = function remove (fn) { if (this._removing) return this; var promise = this._removing = new Promise(fn) , where = this._where() , self = this , options = {} if (this.schema.options.safe) { options.safe = this.schema.options.safe; } this.collection.remove(where, options, tick(function (err) { if (err) { promise.error(err); promise = self = self._removing = where = options = null; return; } self.emit('remove', self); promise.complete(); promise = self = where = options = null; })); return this; };
Parameters:
[fn]
<Function> optional callback
Example:
product.remove(function (err, product) { if (err) return handleError(err); Product.findById(product._id, function (err, product) { console.log(product) // null }) })
Model#_registerHooks()
Register hooks override
show codeModel.prototype._registerHooks = function registerHooks () { Document.prototype._registerHooks.call(this); };
Model#model(
name
)Returns another Model instance.
show codeModel.prototype.model = function model (name) { return this.db.model(name); };
Parameters:
name
<String> model name
Example:
var doc = new Tank; doc.model('User').findById(id, callback);
Model#$where(
argument
)Creates a
Query
and specifies a$where
condition.Returns:
- <Query>
See:
Sometimes you need to query for things in mongodb using a JavaScript expression. You can do so via
find({ $where: javascript })
, or you can use the mongoose shortcut method $where via a Query chain or from your mongoose Model.Blog.$where('this.comments.length > 5');
Model.init()
Called when the model compiles.
show codeModel.init = function init () { if (this.schema.options.autoIndex) this.ensureIndexes(); this.schema.emit('init', this); };
Model.ensureIndexes(
[cb]
)Sends
show codeensureIndex
commands to mongo for each index declared in the schema.Model.ensureIndexes = function ensureIndexes (cb) { var indexes = this.schema.indexes(); if (!indexes.length) { return cb && cb(); } var self = this , safe = self.schema.options.safe , count = indexes.length , error indexes.forEach(function (index) { var options = index[1]; options.safe = safe; self.collection.ensureIndex(index[0], options, tick(function (err) { if (err) error = err; if (--count) return; self.emit('index', error); cb && cb(error); })); }); }
Parameters:
[cb]
<Function> optional callback
After completion, an
index
event is emitted on thisModel
passing an error if one occurred.Model.remove(
conditions
,[callback]
)Removes documents from the collection.
show codeModel.remove = function remove (conditions, callback) { if ('function' === typeof conditions) { callback = conditions; conditions = {}; } var query = new Query(conditions).bind(this, 'remove'); if ('undefined' === typeof callback) return query; this._applyNamedScope(query); return query.remove(callback); };
Returns:
- <Query>
Note:
To remove documents without waiting for a response from MongoDB, do not pass a
callback
, then callexec
on the returned Query:Comment.remove({ _id: id }).exec();
Model.find(
conditions
,[fields]
,[options]
,[callback]
)Finds documents
show codeModel.find = function find (conditions, fields, options, callback) { if ('function' == typeof conditions) { callback = conditions; conditions = {}; fields = null; options = null; } else if ('function' == typeof fields) { callback = fields; fields = null; options = null; } else if ('function' == typeof options) { callback = options; options = null; } var query = new Query(conditions, options); query.bind(this, 'find'); query.select(fields); if ('undefined' === typeof callback) return query; this._applyNamedScope(query); return query.find(callback); };
Parameters:
Returns:
- <Query>
See:
Examples:
// retrieve only certain keys MyModel.find({ name: /john/i }, 'name friends', function () { }) // pass options MyModel.find({ name: /john/i }, null, { skip: 10 } )
Model._applyNamedScope(
query
)Merges the current named scope query into
show codequery
.Model._applyNamedScope = function _applyNamedScope (query) { var cQuery = this._cumulativeQuery; if (cQuery) { merge(query._conditions, cQuery._conditions); if (query._fields && cQuery._fields) merge(query._fields, cQuery._fields); if (query.options && cQuery.options) merge(query.options, cQuery.options); delete this._cumulativeQuery; } return query; }
Parameters:
query
<Query>
Returns:
- <Query>
Model.findById(
id
,[fields]
,[options]
,[callback]
)Finds a single document by id.
show codeModel.findById = function findById (id, fields, options, callback) { return this.findOne({ _id: id }, fields, options, callback); };
Parameters:
Returns:
- <Query>
See:
The
id
is cast to an ObjectId before sending the command.Example:
Adventure.findById(id, callback);
Model.findOne(
conditions
,[fields]
,[options]
,[callback]
)Finds one document.
show codeModel.findOne = function findOne (conditions, fields, options, callback) { if ('function' == typeof options) { // TODO Handle all 3 of the following scenarios // Hint: Only some of these scenarios are possible if cQuery is present // Scenario: findOne(conditions, fields, callback); // Scenario: findOne(fields, options, callback); // Scenario: findOne(conditions, options, callback); callback = options; options = null; } else if ('function' == typeof fields) { // TODO Handle all 2 of the following scenarios // Scenario: findOne(conditions, callback) // Scenario: findOne(fields, callback) // Scenario: findOne(options, callback); callback = fields; fields = null; options = null; } else if ('function' == typeof conditions) { callback = conditions; conditions = {}; fields = null; options = null; } var query = new Query(conditions, options).select(fields).bind(this, 'findOne'); if ('undefined' == typeof callback) return query; this._applyNamedScope(query); return query.findOne(callback); };
Parameters:
Returns:
- <Query>
See:
The
conditions
are cast to their respective SchemaTypes before the command is sent.Example:
Adventure.findOne({ type: 'iphone' }, 'name', { safe: true }, callback);
Model.count(
conditions
,[callback]
)Counts number of matching documents in a database collection.
show codeModel.count = function count (conditions, callback) { if ('function' === typeof conditions) callback = conditions, conditions = {}; var query = new Query(conditions).bind(this, 'count'); if ('undefined' == typeof callback) return query; this._applyNamedScope(query); return query.count(callback); };
Returns:
- <Query>
Example:
Adventure.count({ type: 'jungle' }, function (err, count) { if (err) .. console.log('there are %d jungle adventures', count); });
Model.distinct(
field
,[conditions]
,[callback]
)Executes a DISTINCT command
show codeModel.distinct = function distinct (field, conditions, callback) { var query = new Query(conditions).bind(this, 'distinct'); if ('undefined' == typeof callback) { query._distinctArg = field; return query; } this._applyNamedScope(query); return query.distinct(field, callback); };
Returns:
- <Query>
Model.where(
path
,[val]
)Creates a Query, applies the passed conditions, and returns the Query.
show codeModel.where = function where (path, val) { var q = new Query().bind(this, 'find'); return q.where.apply(q, arguments); };
Returns:
- <Query>
For example, instead of writing:
User.find({age: {$gte: 21, $lte: 65}}, callback);
we can instead write:
User.where('age').gte(21).lte(65).exec(callback);
Since the Query class also supports
where
you can continue chainingUser .where('age').gte(21).lte(65) .where('name', /^b/i) ... etc
Model.findOneAndUpdate(
[conditions]
,[update]
,[options]
,[callback]
)Issues a mongodb findAndModify update command.
show codeModel.findOneAndUpdate = function (conditions, update, options, callback) { if ('function' == typeof options) { callback = options; options = null; } else if (1 === arguments.length) { if ('function' == typeof conditions) { var msg = 'Model.findOneAndUpdate(): First argument must not be a function. ' + ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options, callback) ' + ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options) ' + ' ' + this.modelName + '.findOneAndUpdate(conditions, update) ' + ' ' + this.modelName + '.findOneAndUpdate(update) ' + ' ' + this.modelName + '.findOneAndUpdate() '; throw new TypeError(msg) } update = conditions; conditions = undefined; } var fields; if (options && options.fields) { fields = options.fields; options.fields = undefined; } var query = new Query(conditions); query.setOptions(options); query.select(fields); query.bind(this, 'findOneAndUpdate', update); if ('undefined' == typeof callback) return query; this._applyNamedScope(query); return query.findOneAndUpdate(callback); }
Returns:
- <Query>
See:
Finds a matching document, updates it according to the
update
arg, passing anyoptions
, and returns the found document (if any) to the callback. The query executes immediately ifcallback
is passed else a Query object is returned.Options:
new
: bool - true to return the modified document rather than the original. defaults to trueupsert
: bool - creates the object if it doesn't exist. defaults to false.sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to updateselect
: sets the document fields to return
Examples:
A.findOneAndUpdate(conditions, update, options, callback) // executes A.findOneAndUpdate(conditions, update, options) // returns Query A.findOneAndUpdate(conditions, update, callback) // executes A.findOneAndUpdate(conditions, update) // returns Query A.findOneAndUpdate() // returns Query
Note:
All top level update keys which are not
atomic
operation names are treated as set operations:Example:
var query = { name: 'borne' }; Model.findOneAndUpdate(query, { name: 'jason borne' }, options, callback) // is sent as Model.findOneAndUpdate(query, { $set: { name: 'jason borne' }}, options, callback)
This helps prevent accidentally overwriting your document with
{ name: 'jason borne' }
.Note:
Although values are cast to their appropriate types when using the findAndModify helpers, the following are not applied:
- defaults
- setters
- validators
- middleware
If you need those features, use the traditional approach of first retrieving the document.
Model.findOne({ name: 'borne' }, function (err, doc) { if (err) .. doc.name = 'jason borne'; doc.save(callback); })
Model.findByIdAndUpdate(
id
,[update]
,[options]
,[callback]
)Issues a mongodb findAndModify update command by a documents id.
show codeModel.findByIdAndUpdate = function (id, update, options, callback) { var args; if (1 === arguments.length) { if ('function' == typeof id) { var msg = 'Model.findByIdAndUpdate(): First argument must not be a function. ' + ' ' + this.modelName + '.findByIdAndUpdate(id, callback) ' + ' ' + this.modelName + '.findByIdAndUpdate(id) ' + ' ' + this.modelName + '.findByIdAndUpdate() '; throw new TypeError(msg) } return this.findOneAndUpdate({_id: id }, undefined); } args = utils.args(arguments, 1); args.unshift({ _id: id }); return this.findOneAndUpdate.apply(this, args); }
Parameters:
Returns:
- <Query>
Finds a matching document, updates it according to the
update
arg, passing anyoptions
, and returns the found document (if any) to the callback. The query executes immediately ifcallback
is passed else a Query object is returned.Options:
new
: bool - true to return the modified document rather than the original. defaults to trueupsert
: bool - creates the object if it doesn't exist. defaults to false.sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to updateselect
: sets the document fields to return
Examples:
A.findByIdAndUpdate(id, update, options, callback) // executes A.findByIdAndUpdate(id, update, options) // returns Query A.findByIdAndUpdate(id, update, callback) // executes A.findByIdAndUpdate(id, update) // returns Query A.findByIdAndUpdate() // returns Query
Finds a matching document, updates it according to the
update
arg, passing anyoptions
, and returns the found document (if any) to the callback. The query executes immediately ifcallback
is passed else a Query object is returned.Options:
new
: bool - true to return the modified document rather than the original. defaults to trueupsert
: bool - creates the object if it doesn't exist. defaults to false.sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
Note:
All top level update keys which are not
atomic
operation names are treated as set operations:Example:
Model.findByIdAndUpdate(id, { name: 'jason borne' }, options, callback) // is sent as Model.findByIdAndUpdate(id, { $set: { name: 'jason borne' }}, options, callback)
This helps prevent accidentally overwriting your document with
{ name: 'jason borne' }
.Note:
Although values are cast to their appropriate types when using the findAndModify helpers, the following are not applied:
- defaults
- setters
- validators
- middleware
If you need those features, use the traditional approach of first retrieving the document.
Model.findById(id, function (err, doc) { if (err) .. doc.name = 'jason borne'; doc.save(callback); })
Model.findOneAndRemove(
conditions
,[options]
,[callback]
)Issue a mongodb findAndModify remove command.
show codeModel.findOneAndRemove = function (conditions, options, callback) { if (1 === arguments.length && 'function' == typeof conditions) { var msg = 'Model.findOneAndRemove(): First argument must not be a function. ' + ' ' + this.modelName + '.findOneAndRemove(conditions, callback) ' + ' ' + this.modelName + '.findOneAndRemove(conditions) ' + ' ' + this.modelName + '.findOneAndRemove() '; throw new TypeError(msg) } if ('function' == typeof options) { callback = options; options = undefined; } var fields; if (options) { fields = options.select; options.select = undefined; } var query = new Query(conditions); query.setOptions(options); query.select(fields); query.bind(this, 'findOneAndRemove'); if ('undefined' == typeof callback) return query; this._applyNamedScope(query); return query.findOneAndRemove(callback); }
Returns:
- <Query>
See:
Finds a matching document, removes it, passing the found document (if any) to the callback.
Executes immediately if
callback
is passed else a Query object is returned.Options:
sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to updateselect
: sets the document fields to return
Examples:
A.findOneAndRemove(conditions, options, callback) // executes A.findOneAndRemove(conditions, options) // return Query A.findOneAndRemove(conditions, callback) // executes A.findOneAndRemove(conditions) // returns Query A.findOneAndRemove() // returns Query
Model.findByIdAndRemove(
id
,[options]
,[callback]
)Issue a mongodb findAndModify remove command by a documents id.
show codeModel.findByIdAndRemove = function (id, options, callback) { if (1 === arguments.length && 'function' == typeof id) { var msg = 'Model.findByIdAndRemove(): First argument must not be a function. ' + ' ' + this.modelName + '.findByIdAndRemove(id, callback) ' + ' ' + this.modelName + '.findByIdAndRemove(id) ' + ' ' + this.modelName + '.findByIdAndRemove() '; throw new TypeError(msg) } return this.findOneAndRemove({ _id: id }, options, callback); }
Parameters:
Returns:
- <Query>
Finds a matching document, removes it, passing the found document (if any) to the callback.
Executes immediately if
callback
is passed, else aQuery
object is returned.Options:
sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to updateselect
: sets the document fields to return
Examples:
A.findByIdAndRemove(id, options, callback) // executes A.findByIdAndRemove(id, options) // return Query A.findByIdAndRemove(id, callback) // executes A.findByIdAndRemove(id) // returns Query A.findByIdAndRemove() // returns Query
Model.create(
doc
,fn
)Shortcut for creating a new Document that is automatically saved to the db if valid.
show codeModel.create = function create (doc, fn) { if (1 === arguments.length) { return 'function' === typeof doc && doc(null); } var self = this , docs = [null] , promise , count , args if (Array.isArray(doc)) { args = doc; } else { args = utils.args(arguments, 0, arguments.length - 1); fn = arguments[arguments.length - 1]; } if (0 === args.length) return fn(null); promise = new Promise(fn); count = args.length; args.forEach(function (arg, i) { var doc = new self(arg); docs[i+1] = doc; doc.save(function (err) { if (err) return promise.error(err); --count || fn.apply(null, docs); }); }); // TODO // utilize collection.insertAll for batch processing? };
Example:
Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) { if (err) // ... }); var array = [{ type: 'jelly bean' }, { type: 'snickers' }]; Candy.create(array, function (err, jellybean, snickers) { if (err) // ... });
Model.update(
conditions
,update
,[options]
,[callback]
)Updates documents in the database without returning them.
show codeModel.update = function update (conditions, doc, options, callback) { if (arguments.length < 4) { if ('function' === typeof options) { // Scenario: update(conditions, doc, callback) callback = options; options = null; } else if ('function' === typeof doc) { // Scenario: update(doc, callback); callback = doc; doc = conditions; conditions = {}; options = null; } } var query = new Query(conditions, options).bind(this, 'update', doc); if ('undefined' == typeof callback) return query; this._applyNamedScope(query); return query.update(doc, callback); };
Returns:
- <Query>
Examples:
MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn); MyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, function (err, numberAffected, raw) { if (err) return handleError(err); console.log('The number of updated documents was %d', numberAffected); console.log('The raw response from Mongo was ', raw); });
Valid options:
safe
(boolean) safe mode (defaults to value set in schema (true))upsert
(boolean) whether to create the doc if it doesn't match (false)multi
(boolean) whether multiple documents should be updated (false)
All
update
values are cast to their appropriate SchemaTypes before being sent.The
callback
function receives(err, numberAffected, rawResponse)
.err
is the error if any occurrednumberAffected
is the count of updated documents Mongo reportedrawResponse
is the full response from Mongo
Note:
All top level keys which are not
atomic
operation names are treated as set operations:Example:
var query = { name: 'borne' }; Model.update(query, { name: 'jason borne' }, options, callback) // is sent as Model.update(query, { $set: { name: 'jason borne' }}, options, callback)
This helps prevent accidentally overwriting all documents in your collection with
{ name: 'jason borne' }
.Note:
To update documents without waiting for a response from MongoDB, do not pass a
callback
, then callexec
on the returned Query:Comment.update({ _id: id }, { $set: { text: 'changed' }}).exec();
Note:
Although values are casted to their appropriate types when using update, the following are not applied:
- defaults
- setters
- validators
- middleware
If you need those features, use the traditional approach of first retrieving the document.
Model.findOne({ name: 'borne' }, function (err, doc) { if (err) .. doc.name = 'jason borne'; doc.save(callback); })
Model.mapReduce(
o
,callback
)Executes a mapReduce command.
show codeModel.mapReduce = function mapReduce (o, callback) { if ('function' != typeof callback) throw new Error('missing callback'); var self = this; if (!Model.mapReduce.schema) { var opts = { noId: true, noVirtualId: true, strict: false } Model.mapReduce.schema = new Schema({}, opts); } if (!o.out) o.out = { inline: 1 }; o.map = String(o.map); o.reduce = String(o.reduce); this.collection.mapReduce(null, null, o, function (err, ret, stats) { if (err) return callback(err); if (ret.findOne && ret.mapReduce) { // returned a collection, convert to Model var model = Model.compile( '_mapreduce_' + ret.collectionName , Model.mapReduce.schema , ret.collectionName , self.db , self.base); model._mapreduce = true; return callback(err, model, stats); } callback(err, ret, stats); }); }
o
is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver implementation.Example:
var o = {}; o.map = function () { emit(this.name, 1) } o.reduce = function (k, vals) { return vals.length } User.mapReduce(o, function (err, results) { console.log(results) })
Other options:
query
{Object} query filter object.limit
{Number} max number of documentskeeptemp
{Boolean, default:false} keep temporary datafinalize
{Function} finalize functionscope
{Object} scope variables exposed to map/reduce/finalize during executionjsMode
{Boolean, default:false} it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.Xverbose
{Boolean, default:false} provide statistics on job execution time.out*
{Object, default: {inline:1}} sets the output target for the map reduce job.
* out options:
{inline:1}
the results are returned in an array{replace: 'collectionName'}
add the results to collectionName: the results replace the collection{reduce: 'collectionName'}
add the results to collectionName: if dups are detected, uses the reducer / finalize functions{merge: 'collectionName'}
add the results to collectionName: if dups exist the new docs overwrite the old
If
options.out
is set toreplace
,merge
, orreduce
, a Model instance is returned that can be used for further querying. Queries run against this model are all executed with thelean
option; meaning only the js object is returned and no Mongoose magic is applied (getters, setters, etc).Example:
var o = {}; o.map = function () { emit(this.name, 1) } o.reduce = function (k, vals) { return vals.length } o.out = { replace: 'createdCollectionNameForResults' } o.verbose = true; User.mapReduce(o, function (err, model, stats) { console.log('map reduce took %d ms', stats.processtime) model.find().where('value').gt(10).exec(function (err, docs) { console.log(docs); }); })
- namedscope.js
NamedScope#decorate(
target
,getters
)Decorate
show codeNamedScope.prototype.decorate = function (target, getters) { var name = this.name , block = this.block , query = this.query; if (block) { if (block.length === 0) { Object.defineProperty(target, name, { get: getters.block0(block) }); } else { target[name] = getters.blockN(block); } } else { Object.defineProperty(target, name, { get: getters.basic(query) }); } }; NamedScope.prototype.compile = function (model) { var allScopes = this.scopesByName , scope; for (var k in allScopes) { scope = allScopes[k]; scope.decorate(model, { block0: function (block) { return function () { var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this)); block.call(cquery); return this; }; }, blockN: function (block) { return function () { var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this)); block.apply(cquery, arguments); return this; }; }, basic: function (query) { return function () { var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this)); cquery.find(query); return this; }; } }); } }; module.exports = NamedScope;
Parameters:
target
<NamedScope>getters
<Object>
- promise.js
Promise(
back
)Promise constructor.
show codefunction Promise (back) { this.emitted = {}; if ('function' == typeof back) this.addBack(back); };
Parameters:
back
<Function> a callback+errback that accepts `fn(err, ...){}` as signature
Inherits:
Events:
err
: Emits when the promise resolves to an error.complete
: Emits when the promise resolves sucessfully.
Promise#on(
event
,callback
)Adds
show codelistener
to theevent
.Promise.prototype.on = function (event, callback) { if (this.emitted[event]) callback.apply(this, this.emitted[event]); else EventEmitter.prototype.on.call(this, event, callback); return this; };
Returns:
- <Promise> this
If
event
is eithererror
orcomplete
and the event has already been emitted, thelistener
is called immediately and passed the results of the original emitted event.Promise#emit()
Keeps track of emitted events to run them on
show codeon
.Promise.prototype.emit = function (event) { // ensures a promise can't be complete() or error() twice if (event == 'err' || event == 'complete'){ if (this.emitted.err || this.emitted.complete) { return this; } this.emitted[event] = util.args(arguments, 1); } return EventEmitter.prototype.emit.apply(this, arguments); };
Promise#complete()
Shortcut for emitting the
show codecomplete
event.Promise.prototype.complete = function () { var args = util.args(arguments); return this.emit.apply(this, ['complete'].concat(args)); };
Promise#error()
Shortcut for emitting the
show codeerr
event.Promise.prototype.error = function (err) { if (!(err instanceof Error)) err = new Error(err); return this.emit('err', err); };
Returns:
- <Promise>
Promise#addCallback()
Shortcut for
show code.on('complete', fn)
.Promise.prototype.addCallback = function (fn) { return this.on('complete', fn); };
Returns:
- <Promise>
Promise#addErrback()
Shortcut for
show code.on('err', fn)
.Promise.prototype.addErrback = function (fn) { return this.on('err', fn); };
Returns:
- <Promise>
Promise#addBack(
fn
)Adds a single function that's both a callback and errback.
show codePromise.prototype.addBack = function (fn) { this.on('err', function(err){ fn.call(this, err); }); this.on('complete', function(){ var args = util.args(arguments); fn.apply(this, [null].concat(args)); }); return this; };
Parameters:
fn
<Function>
Returns:
- <Promise>
Promise#resolve(
err
,val
)Sugar for handling cases where you may be resolving to either an error condition or a success condition.
show codePromise.prototype.resolve = function (err, val) { if (err) return this.error(err); return this.complete(val); };
- query.js
Query(
criteria
,options
)Query constructor used for building queries.
show codefunction Query (criteria, options) { this.setOptions(options, true); this._conditions = {}; this._updateArg = {}; if (criteria) this.find(criteria); }
Example:
var query = Model.find(); query.where('age').gte(21).exec(callback);
Query#setOptions(
options
)Sets query options.
show codeQuery.prototype.setOptions = function (options, overwrite) { // overwrite is internal use only if (overwrite) { options = this.options = options || {}; this.safe = options.safe // normalize population options var pop = this.options.populate; this.options.populate = {}; if (pop && Array.isArray(pop)) { for (var i = 0, l = pop.length; i < l; i++) { this.options.populate[pop[i]] = {}; } } return this; } if (!(options && 'Object' == options.constructor.name)) return this; if ('safe' in options) this.safe = options.safe; // set arbitrary options var methods = Object.keys(options) , i = methods.length , method while (i--) { method = methods[i]; // use methods if exist (safer option manipulation) if ('function' == typeof this[method]) { var args = Array.isArray(options[method]) ? options[method] : [options[method]]; this[method].apply(this, args) } else { this.options[method] = options[method]; } } return this; }
Parameters:
options
<Object>
Options:
- tailable *
- sort *
- limit *
- skip *
- maxscan *
- batchSize *
- comment *
- snapshot *
- hint *
- slaveOk *
- lean *
- safe
* denotes a query helper method is also available
Query#bind(
model
,op
,updateArg
)Binds this query to a model.
show codeQuery.prototype.bind = function bind (model, op, updateArg) { this.model = model; this.op = op; if (model._mapreduce) this.options.lean = true; if (op == 'update' || op == 'findOneAndUpdate') { merge(this._updateArg, updateArg || {}); } return this; };
Parameters:
Returns:
- <Query>
Query#exec(
[operation]
,[callback]
)Executes the query
show codeQuery.prototype.exec = function exec (op, callback) { var promise = new Promise(); switch (typeof op) { case 'function': callback = op; op = null; break; case 'string': this.op = op; break; } if (callback) promise.addBack(callback); if (!this.op) { promise.complete(); return promise; } if ('update' == this.op) { this[this.op](this._updateArg, promise.resolve.bind(promise)); return promise; } if ('distinct' == this.op) { this.distinct(this._distinctArg, promise.resolve.bind(promise)); return promise; } this[this.op](promise.resolve.bind(promise)); return promise; };
Returns:
- <Promise>
Examples
query.exec(); query.exec(callback); query.exec('update'); query.exec('find', callback);
Query#find(
[criteria]
,[callback]
)Finds documents.
show codeQuery.prototype.find = function (criteria, callback) { this.op = 'find'; if ('function' === typeof criteria) { callback = criteria; criteria = {}; } else if (criteria instanceof Query) { // TODO Merge options, too merge(this._conditions, criteria._conditions); } else if (criteria instanceof Document) { merge(this._conditions, criteria.toObject()); } else if (criteria && 'Object' === criteria.constructor.name) { merge(this._conditions, criteria); } if (!callback) return this; return this.execFind(callback); };
Returns:
- <Query> this
When no
callback
is passed, the query is not executed.Example
query.find({ name: 'Los Pollos Hermanos' }).find(callback)
Query#cast(
model
,[obj]
)Casts this query to the schema of
show codemodel
Query.prototype.cast = function (model, obj) { obj || (obj= this._conditions); var schema = model.schema , paths = Object.keys(obj) , i = paths.length , any$conditionals , schematype , nested , path , type , val; while (i--) { path = paths[i]; val = obj[path]; if ('$or' === path || '$nor' === path) { var k = val.length , orComponentQuery; while (k--) { orComponentQuery = new Query(val[k]); orComponentQuery.cast(model); val[k] = orComponentQuery._conditions; } } else if (path === '$where') { type = typeof val; if ('string' !== type && 'function' !== type) { throw new Error("Must have a string or function for $where"); } if ('function' === type) { obj[path] = val.toString(); } continue; } else { if (!schema) { // no casting for Mixed types continue; } schematype = schema.path(path); if (!schematype) { // Handle potential embedded array queries var split = path.split('.') , j = split.length , pathFirstHalf , pathLastHalf , remainingConds , castingQuery; // Find the part of the var path that is a path of the Schema while (j--) { pathFirstHalf = split.slice(0, j).join('.'); schematype = schema.path(pathFirstHalf); if (schematype) break; } // If a substring of the input path resolves to an actual real path... if (schematype) { // Apply the casting; similar code for $elemMatch in schema/array.js if (schematype.caster && schematype.caster.schema) { remainingConds = {}; pathLastHalf = split.slice(j).join('.'); remainingConds[pathLastHalf] = val; castingQuery = new Query(remainingConds); castingQuery.cast(schematype.caster); obj[path] = castingQuery._conditions[pathLastHalf]; } else { obj[path] = val; } } } else if (val === null || val === undefined) { continue; } else if ('Object' === val.constructor.name) { any$conditionals = Object.keys(val).some(function (k) { return k.charAt(0) === '$' && k !== '$id' && k !== '$ref'; }); if (!any$conditionals) { obj[path] = schematype.castForQuery(val); } else { var ks = Object.keys(val) , k = ks.length , $cond; while (k--) { $cond = ks[k]; nested = val[$cond]; if ('$exists' === $cond) { if ('boolean' !== typeof nested) { throw new Error("$exists parameter must be Boolean"); } continue; } if ('$type' === $cond) { if ('number' !== typeof nested) { throw new Error("$type parameter must be Number"); } continue; } if ('$not' === $cond) { this.cast(model, nested); } else { val[$cond] = schematype.castForQuery($cond, nested); } } } } else { obj[path] = schematype.castForQuery(val); } } } return obj; };
Returns:
- <Object>
Note
If
obj
is present, it is cast instead of this query.Query#_optionsForExec(
model
)Returns default options.
show codeQuery.prototype._optionsForExec = function (model) { var options = utils.clone(this.options, { retainKeyOrder: true }); delete options.populate; if (! ('safe' in options)) options.safe = model.schema.options.safe; return options; };
Parameters:
model
<Model>
Query#_applyPaths()
Applies schematype selected options to this query.
show codeQuery.prototype._applyPaths = function applyPaths () { // determine if query is selecting or excluding fields var fields = this._fields , exclude , keys , ki if (fields) { keys = Object.keys(fields); ki = keys.length; while (ki--) { if ('+' == keys[ki][0]) continue; exclude = 0 === fields[keys[ki]]; break; } } // if selecting, apply default schematype select:true fields // if excluding, apply schematype select:false fields var selected = [] , excluded = [] , seen = []; analyzeSchema(this.model.schema); switch (exclude) { case true: excluded.length && this.select('-' + excluded.join(' -')); break; case false: selected.length && this.select(selected.join(' ')); break; case undefined: // user didn't specify fields, implies returning all fields. // only need to apply excluded fields excluded.length && this.select('-' + excluded.join(' -')); break; } return seen = excluded = selected = keys = fields = null; function analyzeSchema (schema, prefix) { prefix || (prefix = ''); // avoid recursion if (~seen.indexOf(schema)) return; seen.push(schema); schema.eachPath(function (path, type) { if (prefix) path = prefix + '.' + path; // array of subdocs? if (type.schema) { analyzeSchema(type.schema, path); } analyzePath(path, type); }); } function analyzePath (path, type) { if ('boolean' != typeof type.selected) return; if (fields && ('+' + path) in fields) { // forced inclusion delete fields['+' + path]; // if there are other fields being included, add this one // if no other included fields, leave this out (implied inclusion) if (false === exclude && keys.length > 1) { fields[path] = 1; } return }; ;(type.selected ? selected : excluded).push(path); } }
Query#$where(
js
)Specifies a
$where
conditionReturns:
- <Query> this
Use
$where
when you need to select documents using a JavaScript expression.Example
query.$where('this.comments.length > 10 || this.name.length > 5') query.$where(function () { return this.comments.length > 10 || this.name.length > 5; })
Query#where(
[path]
,[val]
)Specifies a
show codepath
for use with chaining.Query.prototype.where = function (path, val) { if (!arguments.length) return this; if ('string' != typeof path) { throw new TypeError('path must be a string'); } this._currPath = path; if (2 === arguments.length) { this._conditions[path] = val; } return this; };
Returns:
- <Query> this
Example
// instead of writing: User.find({age: {$gte: 21, $lte: 65}}, callback); // we can instead write: User.where('age').gte(21).lte(65); // Moreover, you can also chain a bunch of these together: User .where('age').gte(21).lte(65) .where('name', /^b/i) .where('friends').slice(10) .exec(callback)
Query#equals(
val
)Specifies the complementary comparison value for paths specified with
show codewhere()
Query.prototype.equals = function equals (val) { var path = this._currPath; if (!path) throw new Error('equals() must be used after where()'); this._conditions[path] = val; return this; }
Parameters:
val
<Object>
Returns:
- <Query> this
Example
User.where('age').equals(49); // is the same as User.where('age', 49);
Query#or(
array
)Specifies arguments for an
show code$or
condition.Query.prototype.or = function or (array) { var or = this._conditions.$or || (this._conditions.$or = []); if (!Array.isArray(array)) array = [array]; or.push.apply(or, array); return this; }
Parameters:
array
<Array> array of conditions
Returns:
- <Query> this
Example
query.or([{ color: 'red' }, { status: 'emergency' }])
Query#nor(
array
)Specifies arguments for a
show code$nor
condition.Query.prototype.nor = function nor (array) { var nor = this._conditions.$nor || (this._conditions.$nor = []); if (!Array.isArray(array)) array = [array]; nor.push.apply(nor, array); return this; }
Parameters:
array
<Array> array of conditions
Returns:
- <Query> this
Example
query.nor([{ color: 'green' }, { status: 'ok' }])
Query#gt(
path
,val
)Specifies a $gt query condition.
When called with one argument, the most recent path passed to
where()
is used.Example
Thing.find().where('age').gt(21) // or Thing.find().gt('age', 21)
Query#gte(
path
,val
)Specifies a $gte query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#lt(
path
,val
)Specifies a $lt query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#lte(
path
,val
)Specifies a $lte query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#ne(
path
,val
)Specifies a $ne query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#in(
path
,val
)Specifies an $in query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#nin(
path
,val
)Specifies an $nin query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#all(
path
,val
)Specifies an $all query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#size(
path
,val
)Specifies an $size query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#regex(
path
,val
)Specifies a $regex query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#maxDistance(
path
,val
)Specifies a $maxDistance query condition.
When called with one argument, the most recent path passed to
where()
is used.Query#near(
path
,val
)Specifies a
show code$near
conditionQuery.prototype.near = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath } else if (arguments.length === 2 && !Array.isArray(val)) { val = utils.args(arguments); path = this._currPath; } else if (arguments.length === 3) { val = utils.args(arguments, 1); } var conds = this._conditions[path] || (this._conditions[path] = {}); conds.$near = val; return this; }
Returns:
- <Query> this
Query#nearSphere(
path
,val
)Specifies a
show code$nearSphere
condition.Query.prototype.nearSphere = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath } else if (arguments.length === 2 && !Array.isArray(val)) { val = utils.args(arguments); path = this._currPath; } else if (arguments.length === 3) { val = utils.args(arguments, 1); } var conds = this._conditions[path] || (this._conditions[path] = {}); conds.$nearSphere = val; return this; }
Returns:
- <Query> this
Query#mod(
path
,val
)Specifies a
show code$mod
conditionQuery.prototype.mod = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath } else if (arguments.length === 2 && !Array.isArray(val)) { val = utils.args(arguments); path = this._currPath; } else if (arguments.length === 3) { val = utils.args(arguments, 1); } var conds = this._conditions[path] || (this._conditions[path] = {}); conds.$mod = val; return this; }
Returns:
- <Query> this
Query#exists(
path
,val
)Specifies an
show code$exists
conditionQuery.prototype.exists = function (path, val) { if (arguments.length === 0) { path = this._currPath val = true; } else if (arguments.length === 1) { if ('boolean' === typeof path) { val = path; path = this._currPath; } else { val = true; } } var conds = this._conditions[path] || (this._conditions[path] = {}); conds['$exists'] = val; return this; };
Returns:
- <Query> this
Query#elemMatch(
path
,criteria
)Specifies an
show code$elemMatch
conditionQuery.prototype.elemMatch = function (path, criteria) { var block; if ('Object' === path.constructor.name) { criteria = path; path = this._currPath; } else if ('function' === typeof path) { block = path; path = this._currPath; } else if ('Object' === criteria.constructor.name) { } else if ('function' === typeof criteria) { block = criteria; } else { throw new Error("Argument error"); } var conds = this._conditions[path] || (this._conditions[path] = {}); if (block) { criteria = new Query(); block(criteria); conds['$elemMatch'] = criteria._conditions; } else { conds['$elemMatch'] = criteria; } return this; }; // Spatial queries
Returns:
- <Query> this
Example
query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}}) query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}}) query.elemMatch('comment', function (elem) { elem.where('author').equals('autobot'); elem.where('votes').gte(5); }) query.where('comment').elemMatch(function (elem) { elem.where('author').equals('autobot'); elem.where('votes').gte(5); })
Query#box(
path
,val
)Specifies a $box condition
show codeQuery.prototype.box = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath; } var conds = this._conditions[path] || (this._conditions[path] = {}); conds['$within'] = { '$box': [val.ll, val.ur] }; return this; };
Returns:
- <Query> this
Example
var lowerLeft = [40.73083, -73.99756] var upperRight= [40.741404, -73.988135] query.where('loc').within.box({ ll: lowerLeft , ur: upperRight })
Query#center(
path
,val
,[opts]
)Specifies a $center condition
show codeQuery.prototype.center = function (path, val, opts) { if (arguments.length === 1) { val = path; path = this._currPath; } var conds = this._conditions[path] || (this._conditions[path] = {}); conds['$within'] = { '$center': [val.center, val.radius] }; // copy any options if (opts && 'Object' == opts.constructor.name) { utils.options(opts, conds.$within); } return this; };
Returns:
- <Query> this
Example
var area = { center: [50, 50], radius: 10 } query.where('loc').within.center(area)
Query#centerSphere(
path
,val
)Specifies a $centerSphere condition
show codeQuery.prototype.centerSphere = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath; } var conds = this._conditions[path] || (this._conditions[path] = {}); conds['$within'] = { '$centerSphere': [val.center, val.radius] }; return this; };
Returns:
- <Query> this
Example
var area = { center: [50, 50], radius: 10 } query.where('loc').within.centerSphere(area)
Query#polygon(
path
,val
)Specifies a $polygon condition
show codeQuery.prototype.polygon = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath; } var conds = this._conditions[path] || (this._conditions[path] = {}); conds['$within'] = { '$polygon': val }; return this; };
Returns:
- <Query> this
Example
var polyA = [ [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ] ] query.where('loc').within.polygon(polyA) // or var polyB = { a : { x : 10, y : 20 }, b : { x : 15, y : 25 }, c : { x : 20, y : 20 } } query.where('loc').within.polygon(polyB)
Query#select(
arg
)Specifies which document fields to include or exclude
show codeQuery.prototype.select = function select (arg) { if (!arg) return this; var fields = this._fields || (this._fields = {}); if ('Object' === arg.constructor.name) { Object.keys(arg).forEach(function (field) { fields[field] = arg[field]; }); } else if (1 === arguments.length && 'string' == typeof arg) { arg.split(/\s+/).forEach(function (field) { if (!field) return; var include = '-' == field[0] ? 0 : 1; if (include === 0) field = field.substring(1); fields[field] = include; }); } else { throw new TypeError('Invalid select() argument. Must be a string or object.'); } return this; };
Returns:
- <Query> this
See:
When using string syntax, prefixing a path with
-
will flag that path as excluded. When a path does not have the-
prefix, it is included. Lastly, if a path is prefixed with+
, it forces inclusion of the path, which is useful for paths excluded at the schema level.Example
// include a and b, exclude c query.select('a b -c'); // or you may use object notation, useful when // you have keys already prefixed with a "-" query.select({a: 1, b: 1, c: 0}); // force inclusion of field excluded at schema level query.select('+path')
Query#slice(
path
,val
)Specifies a $slice condition
show codeQuery.prototype.slice = function (path, val) { if (arguments.length === 1) { val = path; path = this._currPath } else if (arguments.length === 2) { if ('number' === typeof path) { val = [path, val]; path = this._currPath; } } else if (arguments.length === 3) { val = utils.args(arguments, 1); } var myFields = this._fields || (this._fields = {}); myFields[path] = { '$slice': val }; return this; };
Returns:
- <Query> this
See:
Example
query.slice('comments', 5) query.slice('comments', -5) query.slice('comments', [10, 5]) query.where('comments').slice(5) query.where('comments').slice([-10, 5])
Query#sort(
arg
)Sets the sort order
show codeQuery.prototype.sort = function (arg) { if (!arg) return this; var sort = this.options.sort || (this.options.sort = []); if ('Object' === arg.constructor.name) { Object.keys(arg).forEach(function (field) { push(sort, field, arg[field]); }); } else if (1 === arguments.length && 'string' == typeof arg) { arg.split(/\s+/).forEach(function (field) { if (!field) return; var ascend = '-' == field[0] ? -1 : 1; if (ascend === -1) field = field.substring(1); push(sort, field, ascend); }); } else { throw new TypeError('Invalid sort() argument. Must be a string or object.'); } return this; };
Returns:
- <Query> this
If an object is passed, values allowed are 'asc', 'desc', 'ascending', 'descending', 1, and -1.
If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with
-
which will be treated as descending.Example
// these are equivalent query.sort({ field: 'asc', test: -1 }); query.sort('field -test');
Query#limit(
val
)Specifies the limit option.
Parameters:
val
<Number>
See:
Example
Kitten.find().limit(20)
Query#skip(
val
)Specifies the skip option.
Parameters:
val
<Number>
See:
Example
Kitten.find().skip(100).limit(20)
Query#maxscan(
val
)Specifies the maxscan option.
Parameters:
val
<Number>
See:
Example
Kitten.find().maxscan(100)
Query#batchSize(
val
)Specifies the batchSize option.
Parameters:
val
<Number>
See:
Example
Kitten.find().batchSize(100)
Query#comment(
val
)Specifies the
comment
option.Parameters:
val
<Number>
See:
Example
Kitten.findOne(condition).comment('login query')
Query#snapshot()
Specifies this query as a
show codesnapshot
query.Query.prototype.snapshot = function () { this.options.snapshot = true; return this; };
Returns:
- <Query> this
See:
Example
Kitten.find().snapshot()
Query#hint(
val
)Sets query hints.
show codeQuery.prototype.hint = function (val) { if (!val) return this; var hint = this.options.hint || (this.options.hint = {}); if ('Object' === val.constructor.name) { // must keep object keys in order so don't use Object.keys() for (var k in val) { hint[k] = val[k]; } } else { throw new TypeError('Invalid hint. ' + val); } return this; };
Parameters:
val
<Object> a hint object
Returns:
- <Query> this
See:
Example
Model.find().hint({ indexA: 1, indexB: -1})
Query#slaveOk(
v
)Sets the slaveOk option.
show codeQuery.prototype.slaveOk = function (v) { this.options.slaveOk = arguments.length ? !!v : true; return this; }
Parameters:
v
<Boolean> defaults to true
Returns:
- <Query> this
See:
Example:
new Query().slaveOk() // true new Query().slaveOk(true) new Query().slaveOk(false)
Query#lean(
v
)Sets the lean option.
show codeQuery.prototype.lean = function (v) { this.options.lean = arguments.length ? !!v : true; return this; }
Parameters:
v
<Boolean> defaults to true
Returns:
- <Query> this
Documents returned from queries with the
lean
option enabled are plain javascript objects, not MongooseDocuments. They have nosave
method, getters/setters or any other Mongoose magic applied.This is a great option in high-performance read-only scenarios, especially when combined with the stream option.
Example:
new Query().lean() // true new Query().lean(true) new Query().lean(false) Model.find().lean().exec(); var leanStream = Model.find().lean().stream();
Query#tailable(
v
)Sets tailable option.
show codeQuery.prototype.tailable = function (v) { this.options.tailable = arguments.length ? !!v : true; return this; };
Parameters:
v
<Boolean> defaults to true
See:
Example
Kitten.find().tailable() <== true Kitten.find().tailable(true) Kitten.find().tailable(false)
Query#execFind(
callback
)Executes the query as a find() operation.
show codeQuery.prototype.execFind = function (callback) { var model = this.model , promise = new Promise(callback); try { this.cast(model); } catch (err) { promise.error(err); return this; } // apply default schematype path selections this._applyPaths(); var self = this , castQuery = this._conditions , options = this._optionsForExec(model) var fields = utils.clone(options.fields = this._fields); model.collection.find(castQuery, options, function (err, cursor) { if (err) return promise.error(err); cursor.toArray(tick(cb)); }); function cb (err, docs) { if (err) return promise.error(err); if (true === options.lean) return promise.complete(docs); var arr = [] , count = docs.length; if (!count) return promise.complete([]); for (var i = 0, l = docs.length; i < l; i++) { arr[i] = new model(undefined, fields, true); arr[i].init(docs[i], self, function (err) { if (err) return promise.error(err); --count || promise.complete(arr); }); } } return this; };
Parameters:
callback
<Function>
Returns:
- <Query> this
Query#findOne(
callback
)Executes the query as a findOne() operation.
show codeQuery.prototype.findOne = function (callback) { this.op = 'findOne'; if (!callback) return this; var model = this.model; var promise = new Promise(callback); try { this.cast(model); } catch (err) { promise.error(err); return this; } // apply default schematype path selections this._applyPaths(); var self = this , castQuery = this._conditions , options = this._optionsForExec(model) var fields = utils.clone(options.fields = this._fields); model.collection.findOne(castQuery, options, tick(function (err, doc) { if (err) return promise.error(err); if (!doc) return promise.complete(null); if (true === options.lean) return promise.complete(doc); var casted = new model(undefined, fields, true); casted.init(doc, self, function (err) { if (err) return promise.error(err); promise.complete(casted); }); })); return this; };
Parameters:
callback
<Function>
Returns:
- <Query> this
Example
Kitten.where('color', 'white').findOne(function (err, kitten) { if (err) return handleError(err); // kitten may be null if no document matched if (kitten) { ... } })
Query#count(
callback
)Exectues the query as a count() operation.
show codeQuery.prototype.count = function (callback) { this.op = 'count'; var model = this.model; try { this.cast(model); } catch (err) { return callback(err); } var castQuery = this._conditions; model.collection.count(castQuery, tick(callback)); return this; };
Parameters:
callback
<Function>
Returns:
- <Query> this
See:
Example
Kitten.where('color', 'black').count(function (err, count) { if (err) return handleError(err); console.log('there are %d black kittens', count); })
Query#distinct(
field
,callback
)Executes this query as a distict() operation.
show codeQuery.prototype.distinct = function (field, callback) { this.op = 'distinct'; var model = this.model; try { this.cast(model); } catch (err) { return callback(err); } var castQuery = this._conditions; model.collection.distinct(field, castQuery, tick(callback)); return this; };
Returns:
- <Query> this
See:
Query#update(
doc
,callback
)Executes this query as an update() operation.
show codeQuery.prototype.update = function update (doc, callback) { this.op = 'update'; this._updateArg = doc; var model = this.model , options = this._optionsForExec(model) , fn = 'function' == typeof callback , castedQuery , castedDoc castedQuery = castQuery(this); if (castedQuery instanceof Error) { if (fn) { process.nextTick(callback.bind(null, castedQuery)); return this; } throw castedQuery; } castedDoc = castDoc(this); if (!castedDoc) { fn && process.nextTick(callback.bind(null, null, 0)); return this; } if (castedDoc instanceof Error) { if (fn) { process.nextTick(callback.bind(null, castedDoc)); return this; } throw castedDoc; } if (!fn) { delete options.safe; } model.collection.update(castedQuery, castedDoc, options, tick(callback)); return this; };
Returns:
- <Query> this
All paths passed that are not $atomic operations will become $set ops so we retain backwards compatibility.
Example
Model.update({..}, { title: 'remove words' }, ...)
becomes
Model.update({..}, { $set: { title: 'remove words' }}, ...)
Note
Passing an empty object
{}
as the doc will result in a no-op. The update operation will be ignored and the callback executed without sending the command to MongoDB so as to prevent accidently overwritting the collection.Query#_castUpdate(
obj
)Casts obj for an update command.
show codeQuery.prototype._castUpdate = function _castUpdate (obj) { var ops = Object.keys(obj) , i = ops.length , ret = {} , hasKeys , val while (i--) { var op = ops[i]; if ('$' !== op[0]) { // fix up $set sugar if (!ret.$set) { if (obj.$set) { ret.$set = obj.$set; } else { ret.$set = {}; } } ret.$set[op] = obj[op]; ops.splice(i, 1); if (!~ops.indexOf('$set')) ops.push('$set'); } else if ('$set' === op) { if (!ret.$set) { ret[op] = obj[op]; } } else { ret[op] = obj[op]; } } // cast each value i = ops.length; while (i--) { op = ops[i]; val = ret[op]; if ('Object' === val.constructor.name) { hasKeys |= this._walkUpdatePath(val, op); } else { var msg = 'Invalid atomic update value for ' + op + '. ' + 'Expected an object, received ' + typeof val; throw new Error(msg); } } return hasKeys && ret; }
Parameters:
obj
<Object>
Returns:
- <Object> obj after casting its values
Query#_walkUpdatePath(
obj
,op
,pref
)Walk each path of obj and cast its values
show code
according to its schema.Query.prototype._walkUpdatePath = function _walkUpdatePath (obj, op, pref) { var strict = this.model.schema.options.strict , prefix = pref ? pref + '.' : '' , keys = Object.keys(obj) , i = keys.length , hasKeys = false , schema , key , val while (i--) { key = keys[i]; val = obj[key]; if (val && 'Object' === val.constructor.name) { // watch for embedded doc schemas schema = this._getSchema(prefix + key); if (schema && schema.caster && op in castOps) { // embedded doc schema if (strict && !schema) { // path is not in our strict schema if ('throw' == strict) { throw new Error('Field `' + key + '` is not in schema.'); } else { // ignore paths not specified in schema delete obj[key]; } } else { hasKeys = true; if ('$each' in val) { obj[key] = { $each: this._castUpdateVal(schema, val.$each, op) } } else { obj[key] = this._castUpdateVal(schema, val, op); } } } else { hasKeys |= this._walkUpdatePath(val, op, prefix + key); } } else { schema = '$each' === key ? this._getSchema(pref) : this._getSchema(prefix + key); var skip = strict && !schema && !/real|nested/.test(this.model.schema.pathType(prefix + key)); if (skip) { if ('throw' == strict) { throw new Error('Field `' + prefix + key + '` is not in schema.'); } else { delete obj[key]; } } else { hasKeys = true; obj[key] = this._castUpdateVal(schema, val, op, key); } } } return hasKeys; }
Parameters:
Returns:
- <Bool> true if this path has keys to update
Query#_castUpdateVal(
schema
,val
,op
,[$conditional]
)Casts
show codeval
according toschema
and atomicop
.Query.prototype._castUpdateVal = function _castUpdateVal (schema, val, op, $conditional) { if (!schema) { // non-existing schema path return op in numberOps ? Number(val) : val } if (schema.caster && op in castOps && ('Object' === val.constructor.name || Array.isArray(val))) { // Cast values for ops that add data to MongoDB. // Ensures embedded documents get ObjectIds etc. var tmp = schema.cast(val); if (Array.isArray(val)) { val = tmp; } else { val = tmp[0]; } } if (op in numberOps) return Number(val); if (/^\$/.test($conditional)) return schema.castForQuery($conditional, val); return schema.castForQuery(val) }
Parameters:
Query#_getSchema(
path
)Finds the schema for
show codepath
. This is different than
callingschema.path
as it also resolves paths with
positional selectors (something.$.another.$.path).Query.prototype._getSchema = function _getSchema (path) { var schema = this.model.schema , pathschema = schema.path(path); if (pathschema) return pathschema; // look for arrays return (function search (parts, schema) { var p = parts.length + 1 , foundschema , trypath while (p--) { trypath = parts.slice(0, p).join('.'); foundschema = schema.path(trypath); if (foundschema) { if (foundschema.caster) { // array of Mixed? if (foundschema.caster instanceof Types.Mixed) { return foundschema.caster; } // Now that we found the array, we need to check if there // are remaining document paths to look up for casting. // Also we need to handle array.$.path since schema.path // doesn't work for that. if (p !== parts.length) { if ('$' === parts[p]) { // comments.$.comments.$.title return search(parts.slice(p+1), foundschema.schema); } else { // this is the last path of the selector return search(parts.slice(p), foundschema.schema); } } } return foundschema; } } })(path.split('.'), schema) }
Parameters:
path
<String>
Query#remove(
callback
)Executes this query as a remove() operation.
show codeQuery.prototype.remove = function (callback) { this.op = 'remove'; var model = this.model , options = this._optionsForExec(model) , cb = 'function' == typeof callback try { this.cast(model); } catch (err) { if (cb) return callback(err); throw err; } if (!cb) { delete options.safe; } var castQuery = this._conditions; model.collection.remove(castQuery, options, tick(callback)); return this; };
Parameters:
callback
<Function>
Example
Cassette.where('artist').equals('Anne Murray').remove(callback)
Query#findOneAndUpdate(
[query]
,[doc]
,[options]
,[callback]
)Issues a mongodb findAndModify update command.
show codeQuery.prototype.findOneAndUpdate = function (query, doc, options, callback) { this.op = 'findOneAndUpdate'; switch (arguments.length) { case 3: if ('function' == typeof options) callback = options, options = {}; break; case 2: if ('function' == typeof doc) { callback = doc; doc = query; query = undefined; } options = undefined; break; case 1: if ('function' == typeof query) { callback = query; query = options = doc = undefined; } else { doc = query; query = options = undefined; } } // apply query if (query) { if ('Object' === query.constructor.name) { merge(this._conditions, query); } else if (query instanceof Query) { merge(this._conditions, query._conditions); } else if (query instanceof Document) { merge(this._conditions, query.toObject()); } } // apply doc if (doc) { merge(this._updateArg, doc); } // apply options options && this.setOptions(options); if (!callback) return this; return this._findAndModify('update', callback); }
Returns:
- <Query> this
See:
Finds a matching document, updates it according to the
update
arg, passing anyoptions
, and returns the found document (if any) to the callback. The query executes immediately ifcallback
is passed else a Query object is returned.Available options
new
: bool - true to return the modified document rather than the original. defaults to trueupsert
: bool - creates the object if it doesn't exist. defaults to false.sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
Examples
query.findOneAndUpdate(conditions, update, options, callback) // executes query.findOneAndUpdate(conditions, update, options) // returns Query query.findOneAndUpdate(conditions, update, callback) // executes query.findOneAndUpdate(conditions, update) // returns Query query.findOneAndUpdate(callback) // executes query.findOneAndUpdate() // returns Query
Query#findOneAndRemove(
[conditions]
,[options]
,[callback]
)Issues a mongodb findAndModify remove command.
show codeQuery.prototype.findOneAndRemove = function (conditions, options, callback) { this.op = 'findOneAndRemove'; if ('function' == typeof options) { callback = options; options = undefined; } else if ('function' == typeof conditions) { callback = conditions; conditions = undefined; } // apply conditions if (conditions) { if ('Object' === conditions.constructor.name) { merge(this._conditions, conditions); } else if (conditions instanceof Query) { merge(this._conditions, conditions._conditions); } else if (conditions instanceof Document) { merge(this._conditions, conditions.toObject()); } } // apply options options && this.setOptions(options); if (!callback) return this; return this._findAndModify('remove', callback); }
Returns:
- <Query> this
See:
Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if
callback
is passed else a Query object is returned.Available options
sort
: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
Examples
A.where().findOneAndRemove(conditions, options, callback) // executes A.where().findOneAndRemove(conditions, options) // return Query A.where().findOneAndRemove(conditions, callback) // executes A.where().findOneAndRemove(conditions) // returns Query A.where().findOneAndRemove(callback) // executes A.where().findOneAndRemove() // returns Query
Query#_findAndModify(
type
,callback
)_findAndModify
show codeQuery.prototype._findAndModify = function (type, callback) { var model = this.model , promise = new Promise(callback) , self = this , castedQuery , castedDoc , fields , sort , opts castedQuery = castQuery(this); if (castedQuery instanceof Error) { process.nextTick(promise.error.bind(promise, castedQuery)); return promise; } opts = this._optionsForExec(model); if ('remove' == type) { opts.remove = true; } else { if (!('new' in opts)) opts.new = true; if (!('upsert' in opts)) opts.upsert = false; castedDoc = castDoc(this); if (!castedDoc) { if (opts.upsert) { // still need to do the upsert to empty doc castedDoc = { $set: {} }; } else { return this.findOne(callback); } } else if (castedDoc instanceof Error) { process.nextTick(promise.error.bind(promise, castedDoc)); return promise; } } if (this._fields) { fields = utils.clone(opts.fields = this._fields); } // the driver needs a default sort = opts.sort || []; model .collection .findAndModify(castedQuery, sort, castedDoc, opts, tick(function (err, doc) { if (err) return promise.error(err); if (!doc) return promise.complete(null); if (true === opts.lean) { return promise.complete(doc); } var casted = new model(undefined, fields, true); casted.init(doc, self, function (err) { if (err) return promise.error(err); promise.complete(casted); }); })); return promise; }
Query#populate(
path
,[fields]
,[model]
,[conditions]
,[options]
)Specifies paths which should be populated with other documents.
show codeQuery.prototype.populate = function (path, fields, model, conditions, options) { if ('string' !== typeof model) { options = conditions; conditions = model; model = undefined; } // The order of fields/conditions args is opposite Model.find but // necessary to keep backward compatibility (fields could be // an array, string, or object literal). this.options.populate[path] = new PopulateOptions(fields, conditions, options, model); return this; };
Parameters:
Returns:
- <Query> this
Paths are populated after the query executes and a response is received. A separate query is then executed for each path specified for population. After a response for each query has also been returned, the results are passed to the callback.
Example:
Kitten.findOne().populate('owner').exec(function (err, kitten) { console.log(kitten.owner.name) // Max })
Query#stream()
Returns a stream interface
show codeQuery.prototype.stream = function stream () { return new QueryStream(this); } // helpers
Returns:
See:
Example
// follows the nodejs stream api Thing.find({ name: /^hello/ }).stream().pipe(res) // manual streaming var stream = Thing.find({ name: /^hello/ }).stream(); stream.on('data', function (doc) { // do something with the mongoose document }).on('error', function (err) { // handle the error }).on('close', function () { // the stream is closed });
Query#within
Syntax sugar for expressive queries.
Example
query.within.box() query.within.center()
Returns:
- <Query> this
- querystream.js
QueryStream(
query
)Provides a ReadStream interface for Queries.
show codefunction QueryStream (query) { Stream.call(this); this.query = query; this.readable = true; this.paused = false; this._cursor = null; this._destroyed = null; this._fields = null; this._ticks = 0; this._inline = T_INIT; // give time to hook up events var self = this; process.nextTick(function () { self._init(); }); }
Parameters:
query
<Query>
Inherits:
Events:
data
: emits a single Mongoose documenterror
: emits when an error occurs during streaming. This will emit before theclose
event.close
: emits when the stream reaches the end of the cursor or an error occurs, or the stream is manuallydestroy
ed. After this event, no more events are emitted.
var stream = Model.find().stream(); stream.on('data', function (doc) { // do something with the mongoose document }).on('error', function (err) { // handle the error }).on('close', function () { // the stream is closed });
The stream interface allows us to simply "plug-in" to other Node streams such as http responses and write streams so everything "just works" out of the box.
Model.where('created').gte(twoWeeksAgo).stream().pipe(writeStream);
QueryStream#_init()
Initializes the query.
show codeQueryStream.prototype._init = function () { if (this._destroyed) return; var query = this.query , model = query.model , options = query._optionsForExec(model) , self = this try { query.cast(model); } catch (err) { return self.destroy(err); } self._fields = utils.clone(options.fields = query._fields); model.collection.find(query._conditions, options, function (err, cursor) { if (err) return self.destroy(err); self._cursor = cursor; self._next(); }); }
QueryStream#_next()
Trampoline for pulling the next doc from cursor.
show codeQueryStream.prototype._next = function () { // avoid stack overflows with large result sets. // trampoline instead of recursion. var fn; while (fn = this.__next()) fn.call(this); }
QueryStream#__next()
Pulls the next doc from the cursor.
show codeQueryStream.prototype.__next = function () { if (this.paused || this._destroyed) return; var self = this; self._inline = T_INIT; self._cursor.nextObject(function (err, doc) { self._onNextObject(err, doc); }); // if onNextObject() was already called in this tick // return ourselves to the trampoline. if (T_CONT === this._inline) { return this.__next; } else { // onNextObject() hasn't fired yet. tell onNextObject // that its ok to call _next b/c we are not within // the trampoline anymore. this._inline = T_IDLE; } }
QueryStream#_onNextObject(
err
,doc
)Transforms raw
show codedoc
s returned from the cursor into a model instance.QueryStream.prototype._onNextObject = function (err, doc) { if (err) return this.destroy(err); // when doc is null we hit the end of the cursor if (!doc) { return this.destroy(); } if (this.query.options && this.query.options.lean === true) { this.emit('data', doc); this._next(); return; } var instance = new this.query.model(undefined, this._fields); // skip _id for pre-init hooks delete instance._doc._id; var self = this; instance.init(doc, this.query, function (err) { if (err) return self.destroy(err); self.emit('data', instance); // trampoline management if (T_IDLE === self._inline) { // no longer in trampoline. restart it. self._next(); } else // in a trampoline. tell __next that its // ok to continue jumping. self._inline = T_CONT; }); }
QueryStream#pause()
Pauses this stream.
show codeQueryStream.prototype.pause = function () { this.paused = true; }
QueryStream#resume()
Resumes this stream.
show codeQueryStream.prototype.resume = function () { this.paused = false; this._next(); }
QueryStream#destroy(
[err]
)Destroys the stream, closing the underlying cursor. No more events will be emitted.
show codeQueryStream.prototype.destroy = function (err) { if (this._destroyed) return; this._destroyed = true; this.readable = false; if (this._cursor) { this._cursor.close(); } if (err) { this.emit('error', err); } this.emit('close'); }
Parameters:
[err]
<Error>
QueryStream#pipe()
Pipes this query stream into another stream. This method is inherited from NodeJS Streams.
See:
Example:
query.stream().pipe(writeStream [, options])
This could be particularily useful if you are, for example, setting up an API for a service and want to stream out the docs based on some criteria. We could first pipe the QueryStream into a sort of filter that formats the stream as an array before passing on the document to an http response.
var format = new ArrayFormatter; Events.find().stream().pipe(format).pipe(res);
As long as ArrayFormat implements the WriteStream API we can stream large formatted result sets out to the client. See this gist for a hacked example.
- schema/array.js
SchemaArray(
key
,cast
,options
)Array SchemaType constructor
show codefunction SchemaArray (key, cast, options) { if (cast) { var castOptions = {}; if ('Object' === cast.constructor.name) { if (cast.type) { // support { type: Woot } castOptions = cast; cast = cast.type; delete castOptions.type; } else { cast = Mixed; } } var caster = cast.name in Types ? Types[cast.name] : cast; this.casterConstructor = caster; this.caster = new caster(null, castOptions); } SchemaType.call(this, key, options); var self = this , defaultArr , fn; if (this.defaultValue) { defaultArr = this.defaultValue; fn = 'function' == typeof defaultArr; } this.default(function(){ var arr = fn ? defaultArr() : defaultArr || []; return new MongooseArray(arr, self.path, this); }); };
Parameters:
key
<String>cast
<SchemaType>options
<Object>
Inherits:
SchemaArray#checkRequired(
value
)Check required
show codeSchemaArray.prototype.checkRequired = function (value) { return !!(value && value.length); };
Parameters:
value
<Array>
SchemaArray#applyGetters(
value
,scope
)Overrides the getters application for the population special-case
show codeSchemaArray.prototype.applyGetters = function (value, scope) { if (this.caster.options && this.caster.options.ref) { // means the object id was populated return value; } return SchemaType.prototype.applyGetters.call(this, value, scope); };
SchemaArray#cast(
value
,doc
,init
)Casts contents
show codeSchemaArray.prototype.cast = function (value, doc, init) { if (Array.isArray(value)) { if (!(value instanceof MongooseArray)) { value = new MongooseArray(value, this.path, doc); } if (this.caster) { try { for (var i = 0, l = value.length; i < l; i++) { value[i] = this.caster.cast(value[i], doc, init); } } catch (e) { // rethrow throw new CastError(e.type, value); } } return value; } else { return this.cast([value], doc, init); } };
Parameters:
SchemaArray#castForQuery(
$conditional
,[value]
)Casts contents for queries.
show codeSchemaArray.prototype.castForQuery = function ($conditional, value) { var handler , val; if (arguments.length === 2) { handler = this.$conditionalHandlers[$conditional]; if (!handler) throw new Error("Can't use " + $conditional + " with Array."); val = handler.call(this, value); } else { val = $conditional; var proto = this.casterConstructor.prototype; var method = proto.castForQuery || proto.cast; if (Array.isArray(val)) { val = val.map(function (v) { if (method) v = method.call(proto, v); return isMongooseObject(v) ? v.toObject() : v; }); } else if (method) { val = method.call(proto, val); } } return val && isMongooseObject(val) ? val.toObject() : val; };
- schema/boolean.js
SchemaBoolean(
path
,options
)Boolean SchemaType constructor.
show codefunction SchemaBoolean (path, options) { SchemaType.call(this, path, options); };
Inherits:
SchemaBoolean#checkRequired()
Required validator
show codeSchemaBoolean.prototype.checkRequired = function (value) { return value === true || value === false; };
SchemaBoolean#cast(
value
)Casts to boolean
show codeSchemaBoolean.prototype.cast = function (value) { if (value === null) return value; if (value === '0') return false; return !!value; };
Parameters:
value
<Object>
SchemaBoolean#castForQuery(
$conditional
,val
)Casts contents for queries.
show codeSchemaBoolean.prototype.castForQuery = function ($conditional, val) { var handler; if (2 === arguments.length) { handler = SchemaBoolean.$conditionalHandlers[$conditional]; if (!handler) throw new Error("Can't use " + $conditional + " with Boolean."); return handler.call(this, val); } return this.cast($conditional); };
- schema/buffer.js
SchemaBuffer(
key
,cast
)Buffer SchemaType constructor
show codefunction SchemaBuffer (key, options) { SchemaType.call(this, key, options, 'Buffer'); };
Parameters:
key
<String>cast
<SchemaType>
Inherits:
SchemaBuffer#checkRequired()
Check required
show codeSchemaBuffer.prototype.checkRequired = function (value) { return !!(value && value.length); };
SchemaBuffer#cast(
value
,doc
,init
)Casts contents
show codeSchemaBuffer.prototype.cast = function (value, doc, init) { if (SchemaType._isRef(this, value, init)) return value; if (Buffer.isBuffer(value)) { if (!(value instanceof MongooseBuffer)) { value = new MongooseBuffer(value, [this.path, doc]); } return value; } else if (value instanceof Binary) { return new MongooseBuffer(value.value(true), [this.path, doc]); } if ('string' === typeof value || Array.isArray(value)) { return new MongooseBuffer(value, [this.path, doc]); } throw new CastError('buffer', value); };
SchemaBuffer#castForQuery(
$conditional
,[value]
)Casts contents for queries.
show codeSchemaBuffer.prototype.castForQuery = function ($conditional, val) { var handler; if (arguments.length === 2) { handler = this.$conditionalHandlers[$conditional]; if (!handler) throw new Error("Can't use " + $conditional + " with Buffer."); return handler.call(this, val); } else { val = $conditional; return this.cast(val).toObject(); } };
- schema/date.js
SchemaDate(
key
,options
)Date SchemaType constructor.
show codefunction SchemaDate (key, options) { SchemaType.call(this, key, options); };
Inherits:
SchemaDate#checkRequired()
Required validator for date
show codeSchemaDate.prototype.checkRequired = function (value) { return value instanceof Date; };
SchemaDate#cast(
value
)Casts to date
show codeSchemaDate.prototype.cast = function (value) { if (value === null || value === '') return null; if (value instanceof Date) return value; var date; // support for timestamps if (value instanceof Number || 'number' == typeof value || String(value) == Number(value)) date = new Date(Number(value)); // support for date strings else if (value.toString) date = new Date(value.toString()); if (date.toString() != 'Invalid Date') return date; throw new CastError('date', value); };
Parameters:
value
<Object> to cast
SchemaDate#castForQuery(
$conditional
,[value]
)Casts contents for queries.
show codeSchemaDate.prototype.castForQuery = function ($conditional, val) { var handler; if (2 !== arguments.length) { return this.cast($conditional); } handler = this.$conditionalHandlers[$conditional]; if (!handler) { throw new Error("Can't use " + $conditional + " with Date."); } return handler.call(this, val); };
- schema/documentarray.js
DocumentArray(
key
,schema
,options
)SubdocsArray SchemaType constructor
show codefunction DocumentArray (key, schema, options) { // compile an embedded document for this schema // TODO Move this into parent model compilation for performance improvement? function EmbeddedDocument () { Subdocument.apply(this, arguments); }; EmbeddedDocument.prototype.__proto__ = Subdocument.prototype; EmbeddedDocument.prototype._setSchema(schema); EmbeddedDocument.schema = schema; // apply methods for (var i in schema.methods) { EmbeddedDocument.prototype[i] = schema.methods[i]; } // apply statics for (var i in schema.statics) EmbeddedDocument[i] = schema.statics[i]; EmbeddedDocument.options = options; this.schema = schema; ArrayType.call(this, key, EmbeddedDocument, options); this.schema = schema; var path = this.path; var fn = this.defaultValue; this.default(function(){ var arr = fn.call(this); if (!Array.isArray(arr)) arr = [arr]; return new MongooseDocumentArray(arr, path, this); }); };
Inherits:
DocumentArray#doValidate()
Performs local validations first, then validations on each embedded doc
show codeDocumentArray.prototype.doValidate = function (array, fn, scope) { var self = this; SchemaType.prototype.doValidate.call(this, array, function(err){ if (err) return fn(err); var count = array && array.length , error = false; if (!count) return fn(); array.forEach(function(doc, index){ doc.validate(function(err){ if (err && !error){ // rewrite they key err.key = self.key + '.' + index + '.' + err.key; fn(err); error = true; } else { --count || fn(); } }); }); }, scope); };
DocumentArray#cast(
value
,document
)Casts contents
show codeDocumentArray.prototype.cast = function (value, doc, init, prev) { var subdoc , i if (Array.isArray(value)) { if (!(value instanceof MongooseDocumentArray)) { value = new MongooseDocumentArray(value, this.path, doc); } i = value.length; while (i--) { if (!(value[i] instanceof Subdocument)) { if (init) { subdoc = new this.casterConstructor(null, value, true); value[i] = subdoc.init(value[i]); } else { if (prev && (subdoc = prev.id(value[i]._id))) { // handle resetting doc with existing id but differing data // doc.array = [{ doc: 'val' }] subdoc.set(value[i]); } else { subdoc = new this.casterConstructor(value[i], value); } // if set() is hooked it will have no return value // see gh-746 value[i] = subdoc; } } } return value; } else { return this.cast([value], doc, init, prev); } throw new CastError('documentarray', value); };
- schema/mixed.js
Mixed(
path
,options
)Mixed SchemaType constructor.
show codefunction Mixed (path, options) { // make sure empty array defaults are handled if (options && options.default && Array.isArray(options.default) && 0 === options.default.length) { options.default = Array; } SchemaType.call(this, path, options); };
Inherits:
Mixed#checkRequired()
Required validator
show codeMixed.prototype.checkRequired = function (val) { return true; };
Mixed#cast(
value
)Casts
show codeval
for Mixed.Mixed.prototype.cast = function (val) { return val; };
Parameters:
value
<Object> to cast
this is a no-op
Mixed#castForQuery(
$cond
,[val]
)Casts contents for queries.
show codeMixed.prototype.castForQuery = function ($cond, val) { if (arguments.length === 2) return val; return $cond; };
- schema/number.js
SchemaNumber(
key
,options
)Number SchemaType constructor.
show codefunction SchemaNumber (key, options) { SchemaType.call(this, key, options, 'Number'); };
Inherits:
SchemaNumber#checkRequired()
Required validator for number
show codeSchemaNumber.prototype.checkRequired = function checkRequired (value) { if (SchemaType._isRef(this, value, true)) { return null != value; } else { return typeof value == 'number' || value instanceof Number; } };
SchemaNumber#min(
value
,message
)Sets a maximum number validator.
show codeSchemaNumber.prototype.min = function (value, message) { if (this.minValidator) this.validators = this.validators.filter(function(v){ return v[1] != 'min'; }); if (value != null) this.validators.push([function(v){ return v === null || v >= value; }, 'min']); return this; };
Example:
var s = new Schema({ n: { type: Number, min: 10 }) var M = db.model('M', s) var m = new M({ n: 9 }) m.save(function (err) { console.error(err) // validator error m.n = 10; m.save() // success })
SchemaNumber#max(
maximum
,message
)Sets a maximum number validator.
show codeSchemaNumber.prototype.max = function (value, message) { if (this.maxValidator) this.validators = this.validators.filter(function(v){ return v[1] != 'max'; }); if (value != null) this.validators.push([this.maxValidator = function(v){ return v === null || v <= value; }, 'max']); return this; };
Example:
var s = new Schema({ n: { type: Number, max: 10 }) var M = db.model('M', s) var m = new M({ n: 11 }) m.save(function (err) { console.error(err) // validator error m.n = 10; m.save() // success })
SchemaNumber#cast(
value
,doc
,init
)Casts to number
show codeSchemaNumber.prototype.cast = function (value, doc, init) { if (SchemaType._isRef(this, value, init)) return value; if (!isNaN(value)){ if (null === value) return value; if ('' === value) return null; if ('string' == typeof value) value = Number(value); if (value instanceof Number) return value if ('number' == typeof value) return value; if (value.toString && !Array.isArray(value) && value.toString() == Number(value)) { return new Number(value) } } throw new CastError('number', value); };
Parameters:
SchemaNumber#castForQuery(
$conditional
,[value]
)Casts contents for queries.
show codeSchemaNumber.prototype.castForQuery = function ($conditional, val) { var handler; if (arguments.length === 2) { handler = this.$conditionalHandlers[$conditional]; if (!handler) throw new Error("Can't use " + $conditional + " with Number."); return handler.call(this, val); } else { val = this.cast($conditional); return val == null ? val : val } };
- schema/objectid.js
ObjectId(
key
,options
)ObjectId SchemaType constructor.
show codefunction ObjectId (key, options) { SchemaType.call(this, key, options, 'ObjectID'); };
Inherits:
ObjectId#checkRequired()
Check required
show codeObjectId.prototype.checkRequired = function checkRequired (value) { if (SchemaType._isRef(this, value, true)) { return null != value; } else { return value instanceof oid; } };
ObjectId#cast(
value
,scope
,init
)Casts to ObjectId
show codeObjectId.prototype.cast = function (value, scope, init) { if (SchemaType._isRef(this, value, init)) return value; if (value === null) return value; if (value instanceof oid) return value; if (value._id && value._id instanceof oid) return value._id; if (value.toString) return oid.fromString(value.toString()); throw new CastError('object id', value); };
ObjectId#castForQuery(
$conditional
,[val]
)Casts contents for queries.
show codeObjectId.prototype.castForQuery = function ($conditional, val) { var handler; if (arguments.length === 2) { handler = this.$conditionalHandlers[$conditional]; if (!handler) throw new Error("Can't use " + $conditional + " with ObjectId."); return handler.call(this, val); } else { return this.cast($conditional); } };
ObjectId#auto(
turnOn
)Adds an auto-generated ObjectId default if turnOn is true.
show codeObjectId.prototype.auto = function (turnOn) { if (turnOn) { this.default(defaultId); this.set(resetId) } };
Parameters:
turnOn
<Boolean> auto generated ObjectId defaults
- schema/string.js
SchemaString(
key
,options
)String SchemaType constructor.
show codefunction SchemaString (key, options) { this.enumValues = []; this.regExp = null; SchemaType.call(this, key, options, 'String'); };
Inherits:
SchemaString#enum(
[args...]
)Adds enumeration values and a coinciding validator.
show codeSchemaString.prototype.enum = function () { var len = arguments.length; if (!len || undefined === arguments[0] || false === arguments[0]) { if (this.enumValidator){ this.enumValidator = false; this.validators = this.validators.filter(function(v){ return v[1] != 'enum'; }); } return; } for (var i = 0; i < len; i++) { if (undefined !== arguments[i]) { this.enumValues.push(this.cast(arguments[i])); } } if (!this.enumValidator) { var values = this.enumValues; this.enumValidator = function(v){ return undefined === v || ~values.indexOf(v); }; this.validators.push([this.enumValidator, 'enum']); } };
Parameters:
[args...]
<String> enumeration values
Example:
var states = 'opening open closing closed'.split(' ') var s = new Schema({ state: { type: String, enum: states }) var M = db.model('M', s) var m = new M({ state: 'invalid' }) m.save(function (err) { console.error(err) // validator error m.state = 'open' m.save() // success })
SchemaString#lowercase()
Adds a lowercase setter.
show codeSchemaString.prototype.lowercase = function () { return this.set(function (v) { return v.toLowerCase(); }); };
Example:
var s = new Schema({ email: { type: String, lowercase: true }}) var M = db.model('M', s); var m = new M({ email: 'SomeEmail@example.COM' }); console.log(m.email) // someemail@example.com
SchemaString#uppercase()
Adds an uppercase setter.
show codeSchemaString.prototype.uppercase = function () { return this.set(function (v) { return v.toUpperCase(); }); };
Example:
var s = new Schema({ caps: { type: String, uppercase: true }}) var M = db.model('M', s); var m = new M({ caps: 'an example' }); console.log(m.caps) // AN EXAMPLE
SchemaString#trim()
Adds a trim setter.
show codeSchemaString.prototype.trim = function () { return this.set(function (v) { return v.trim(); }); };
The string value will be trimmed when set.
Example:
var s = new Schema({ name: { type: String, trim: true }}) var M = db.model('M', s) var string = ' some name ' console.log(string.length) // 11 var m = new M({ name: string }) console.log(m.name.length) // 9
SchemaString#match(
regExp
)Sets a regexp validator.
show codeSchemaString.prototype.match = function match (regExp) { this.validators.push([function(v){ return null != v && '' !== v ? regExp.test(v) : true }, 'regexp']); };
Parameters:
regExp
<RegExp> regular expression to test against
Any value that does not pass
regExp
.test(val) will fail validation.Example:
var s = new Schema({ name: { type: String, match: /^a/ }}) var M = db.model('M', s) var m = new M({ name: 'invalid' }) m.validate(function (err) { console.error(err) // validation error m.name = 'apples' m.validate(function (err) { assert.ok(err) // success }) })
SchemaString#checkRequired(
value
)Check required
show codeSchemaString.prototype.checkRequired = function checkRequired (value) { if (SchemaType._isRef(this, value, true)) { return null != value; } else { return (value instanceof String || typeof value == 'string') && value.length; } };
SchemaString#cast()
Casts to String
show codeSchemaString.prototype.cast = function (value, scope, init) { if (SchemaType._isRef(this, value, init)) return value; if (value === null) return value; if ('undefined' !== typeof value && value.toString) return value.toString(); throw new CastError('string', value); };
SchemaString#castForQuery(
$conditional
,[val]
)Casts contents for queries.
show codeSchemaString.prototype.castForQuery = function ($conditional, val) { var handler; if (arguments.length === 2) { handler = this.$conditionalHandlers[$conditional]; if (!handler) throw new Error("Can't use " + $conditional + " with String."); return handler.call(this, val); } else { val = $conditional; if (val instanceof RegExp) return val; return this.cast(val); } };
- schema.js
Schema(
definition
)Schema constructor.
show codefunction Schema (obj, options) { if (!(this instanceof Schema)) return new Schema(obj, options); this.paths = {}; this.subpaths = {}; this.virtuals = {}; this.nested = {}; this.inherits = {}; this.callQueue = []; this._indexes = []; this.methods = {}; this.statics = {}; this.tree = {}; this._requiredpaths = undefined; // set options this.options = utils.options({ safe: true , strict: true , capped: false // { size, max, autoIndexId } , versionKey: '__v' , minimize: true , autoIndex: true , shardKey: null // the following are only applied at construction time , noId: false // deprecated, use { _id: false } , _id: true , noVirtualId: false // deprecated, use { id: false } , id: true }, options); // build paths if (obj) { this.add(obj); } // ensure the documents get an auto _id unless disabled var auto_id = !this.paths['_id'] && (!this.options.noId && this.options._id); if (auto_id) { this.add({ _id: {type: Schema.ObjectId, auto: true} }); } // ensure the documents receive an id getter unless disabled var autoid = !this.paths['id'] && (!this.options.noVirtualId && this.options.id); if (autoid) { this.virtual('id').get(idGetter); } // versioning not directly added to schema b/c we only want // it in the top level document, not embedded ones. };
Parameters:
definition
<Object>
Inherits:
Events:
init
: Emitted after the schema is compiled into aModel
.
Example:
var child = new Schema({ name: String }); var schema = new Schema({ name: String, age: Number, children: [child] }); var Tree = mongoose.model('Tree', schema); // setting schema options new Schema({ name: String }, { _id: false, autoIndex: false })
Options:
- safe: bool - defaults to true.
- strict: bool - defaults to true
- capped: bool - defaults to false
- versionKey: bool - defaults to "__v"
- shardKey: bool - defaults to
null
- autoIndex: bool - defaults to true
- _id: bool - defaults to true
- id: bool - defaults to true
minimize
: bool - controls document#toObject behavior when called manually - defaults to true
Note:
When nesting schemas, (
children
in the example above), always declare the child schema first before passing it into is parent.Schema#add(
obj
,prefix
)Adds key path / schema type pairs to this schema.
show codeSchema.prototype.add = function add (obj, prefix) { prefix = prefix || ''; for (var i in obj) { if (null == obj[i]) { throw new TypeError('Invalid value for schema path `'+ prefix + i +'`'); } if (obj[i].constructor.name == 'Object' && (!obj[i].type || obj[i].type.type)) { if (Object.keys(obj[i]).length) { // nested object { last: { name: String }} this.nested[prefix + i] = true; this.add(obj[i], prefix + i + '.'); } else this.path(prefix + i, obj[i]); // mixed type } else this.path(prefix + i, obj[i]); } };
Example:
var ToySchema = new Schema; ToySchema.add({ name: 'string', color: 'string', price: 'number' });
Schema#path(
path
,constructor
)Gets/sets schema paths.
show codeSchema.prototype.path = function (path, obj) { if (obj == undefined) { if (this.paths[path]) return this.paths[path]; if (this.subpaths[path]) return this.subpaths[path]; // subpaths? return /\.\d+\.?$/.test(path) ? getPositionalPath(this, path) : undefined; } // some path names conflict with document methods if (reserved[path]) { throw new Error("`" + path + "` may not be used as a schema pathname"); } // update the tree var subpaths = path.split(/\./) , last = subpaths.pop() , branch = this.tree; subpaths.forEach(function(path) { if (!branch[path]) branch[path] = {}; branch = branch[path]; }); branch[last] = utils.clone(obj); this.paths[path] = Schema.interpretAsType(path, obj); return this; };
Sets a path (if arity 2)
Gets a path (if arity 1)Example
schema.path('name') // returns a SchemaType schema.path('name', Number) // changes the schemaType of `name` to Number
Schema#eachPath(
fn
)Iterates the schemas paths similar to Array#forEach.
show codeSchema.prototype.eachPath = function (fn) { var keys = Object.keys(this.paths) , len = keys.length; for (var i = 0; i < len; ++i) { fn(keys[i], this.paths[keys[i]]); } return this; };
Parameters:
fn
<Function> callback function
Returns:
- <Schema> this
The callback is passed the pathname and schemaType as arguments on each iteration.
Schema#requiredPaths()
Returns an Array of path strings that are required by this schema.
show codeSchema.prototype.requiredPaths = function requiredPaths () { if (this._requiredpaths) return this._requiredpaths; var paths = Object.keys(this.paths) , i = paths.length , ret = []; while (i--) { var path = paths[i]; if (this.paths[path].isRequired) ret.push(path); } return this._requiredpaths = ret; }
Returns:
- <Array>
Schema#pathType(
path
)Returns the pathType of
show codepath
for this schema.Schema.prototype.pathType = function (path) { if (path in this.paths) return 'real'; if (path in this.virtuals) return 'virtual'; if (path in this.nested) return 'nested'; if (path in this.subpaths) return 'real'; if (/\.\d+\.?/.test(path) && getPositionalPath(this, path)) { return 'real'; } else { return 'adhocOrUndefined' } };
Parameters:
path
<String>
Returns:
- <String>
Given a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path.
Schema#queue(
name
,args
)Adds a method call to the queue.
show codeSchema.prototype.queue = function(name, args){ this.callQueue.push([name, args]); return this; };
Parameters:
Schema#pre(
method
,callback
)Defines a pre hook for the document.
show codeSchema.prototype.pre = function(){ return this.queue('pre', arguments); };
See:
Example
var toySchema = new Schema(..); toySchema.pre('save', function (next) { if (!this.created) this.created = new Date; next(); }) toySchema.pre('validate', function (next) { if (this.name != 'Woody') this.name = 'Woody'; next(); })
Schema#post(
method
,fn
)Defines a post hook for the document.
show codeSchema.prototype.post = function(method, fn){ return this.queue('on', arguments); };
See:
Post hooks fire
on
the event emitted from document instances of Models compiled from this schema.var schema = new Schema(..); schema.post('save', function () { console.log('this fired after a document was saved'); }); var Model = mongoose.model('Model', schema); var m = new Model(..); m.save(function (err) { console.log('this fires after the `post` hook'); });
Schema#plugin(
plugin
,opts
)Registers a plugin for this schema.
show codeSchema.prototype.plugin = function (fn, opts) { fn(this, opts); return this; };
See:
Schema#method(
method
,[fn]
)Adds an instance method to documents constructed from Models compiled from this schema.
show codeSchema.prototype.method = function (name, fn) { if ('string' != typeof name) for (var i in name) this.methods[i] = name[i]; else this.methods[name] = fn; return this; };
Example
var schema = kittySchema = new Schema(..); schema.methods.meow = function () { console.log('meeeeeoooooooooooow'); }) var Kitty = mongoose.model('Kitty', schema); var fizz = new Kitty; fizz.meow(); // meeeeeooooooooooooow
If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.
schema.method({ purr: function () {} , scratch: function () {} }); // later fizz.purr(); fizz.scratch();
Schema#static(
name
,fn
)Adds static "class" methods to Models compiled from this schema.
show codeSchema.prototype.static = function(name, fn) { if ('string' != typeof name) for (var i in name) this.statics[i] = name[i]; else this.statics[name] = fn; return this; };
Example
var schema = new Schema(..); schema.static('findByName', function (name, callback) { return this.find({ name: name }, callback); }); var Drink = mongoose.model('Drink', schema); Drink.findByName('sanpellegrino', function (err, drinks) { // });
If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.
Schema#index(
fields
,[options]
)Defines an index (most likely compound) for this schema.
show codeSchema.prototype.index = function (fields, options) { options || (options = {}); if (options.expires) utils.expires(options); this._indexes.push([fields, options]); return this; };
Example
schema.index({ first: 1, last: -1 })
Schema#set(
key
,[value]
)Sets/gets a schema option.
show codeSchema.prototype.set = function (key, value) { if (arguments.length == 1) return this.options[key]; this.options[key] = value; return this; };
Parameters:
Schema#indexes()
Compiles indexes from fields and schema-level indexes
show codeSchema.prototype.indexes = function () { var indexes = [] , seenSchemas = []; collectIndexes(this); return indexes; function collectIndexes (schema, prefix) { if (~seenSchemas.indexOf(schema)) return; seenSchemas.push(schema); var index; var paths = schema.paths; prefix = prefix || ''; for (var i in paths) { if (paths[i]) { if (paths[i] instanceof Types.DocumentArray) { collectIndexes(paths[i].schema, i + '.'); } else { index = paths[i]._index; if (index !== false && index !== null){ var field = {}; field[prefix + i] = '2d' === index ? index : 1; var options = 'Object' === index.constructor.name ? index : {}; if (!('background' in options)) options.background = true; indexes.push([field, options]); } } } } if (prefix) { fixSubIndexPaths(schema, prefix); } else { schema._indexes.forEach(function (index) { if (!('background' in index[1])) index[1].background = true; }); indexes = indexes.concat(schema._indexes); } }
Schema#virtual(
name
,[options]
)Creates a virtual type with the given name.
show codeSchema.prototype.virtual = function (name, options) { var virtuals = this.virtuals; var parts = name.split('.'); return virtuals[name] = parts.reduce(function (mem, part, i) { mem[part] || (mem[part] = (i === parts.length-1) ? new VirtualType(options) : {}); return mem[part]; }, this.tree); };
Returns:
Schema#virtualpath(
name
)Returns the virtual type with the given
show codename
.Schema.prototype.virtualpath = function (name) { return this.virtuals[name]; };
Parameters:
name
<String>
Returns:
Schema#namedScope()
These still haven't been fixed. Once they're working we'll make them public again.
show codeSchema.prototype.namedScope = function (name, fn) { var namedScopes = this.namedScopes || (this.namedScopes = new NamedScope) , newScope = Object.create(namedScopes) , allScopes = namedScopes.scopesByName || (namedScopes.scopesByName = {}); allScopes[name] = newScope; newScope.name = name; newScope.block = fn; newScope.query = new Query(); newScope.decorate(namedScopes, { block0: function (block) { return function () { block.call(this.query); return this; }; }, blockN: function (block) { return function () { block.apply(this.query, arguments); return this; }; }, basic: function (query) { return function () { this.query.find(query); return this; }; } }); return newScope; };
Schema.reserved
Reserved document keys.
show codeSchema.reserved = Object.create(null); var reserved = Schema.reserved; reserved.on = reserved.db = reserved.init = reserved.isNew = reserved.errors = reserved.schema = reserved.options = reserved.modelName = reserved.collection = 1;
Keys in this object are names that are rejected in schema declarations b/c they conflict with mongoose functionality. Using these key name will throw an error.
on, db, init, isNew, errors, schema, options, modelName, collection
Schema.interpretAsType(
path
,obj
)Converts type arguments into Mongoose Types.
show codeSchema.interpretAsType = function (path, obj) { if (obj.constructor.name != 'Object') obj = { type: obj }; // Get the type making sure to allow keys named "type" // and default to mixed if not specified. // { type: { type: String, default: 'freshcut' } } var type = obj.type && !obj.type.type ? obj.type : {}; if ('Object' == type.constructor.name || 'mixed' == type) { return new Types.Mixed(path, obj); } if (Array.isArray(type) || Array == type || 'array' == type) { // if it was specified through { type } look for `cast` var cast = (Array == type || 'array' == type) ? obj.cast : type[0]; if (cast instanceof Schema) { return new Types.DocumentArray(path, cast, obj); } if ('string' == typeof cast) { cast = Types[cast.charAt(0).toUpperCase() + cast.substring(1)]; } else if (cast && (!cast.type || cast.type.type) && 'Object' == cast.constructor.name && Object.keys(cast).length) { return new Types.DocumentArray(path, new Schema(cast), obj); } return new Types.Array(path, cast || Types.Mixed, obj); } var name = 'string' == typeof type ? type : type.name; if (name) { name = name.charAt(0).toUpperCase() + name.substring(1); } if (undefined == Types[name]) { throw new TypeError('Undefined type at `' + path + '` Did you try nesting Schemas? ' + 'You can only nest using refs or arrays.'); } return new Types[name](path, obj); };
Schema.Types
The various Mongoose Schema Types.
show codeSchema.Types = require('./schema/index');
Example:
Example:
var mongoose = require('mongoose'); var ObjectId = mongoose.Schema.Types.ObjectId;
Types:
- String
- Number
- Boolean | Bool
- Array
- Buffer
- Date
- ObjectId | Oid
- Mixed
Using this exposed access to the
Mixed
SchemaType, we can use them in our schema.var Mixed = mongoose.Schema.Types.Mixed; new mongoose.Schema({ _user: Mixed })
- schemadefault.js
- schematype.js
SchemaType(
path
,[options]
,[instance]
)SchemaType constructor
show codefunction SchemaType (path, options, instance) { this.path = path; this.instance = instance; this.validators = []; this.setters = []; this.getters = []; this.options = options; this._index = null; this.selected; for (var i in options) if (this[i] && 'function' == typeof this[i]) { // { unique: true, index: true } if ('index' == i && this._index) continue; var opts = Array.isArray(options[i]) ? options[i] : [options[i]]; this[i].apply(this, opts); } };
SchemaType#default(
val
)Sets a default value for this SchemaType.
show codeSchemaType.prototype.default = function (val) { if (1 === arguments.length) { this.defaultValue = typeof val === 'function' ? val : this.cast(val); return this; } else if (arguments.length > 1) { this.defaultValue = utils.args(arguments); } return this.defaultValue; };
Returns:
Example:
var schema = new Schema({ n: { type: Number, default: 10 }) var M = db.model('M', schema) var m = new M; console.log(m.n) // 10
Defaults can be either
functions
which return the value to use as the default or the literal value itself. Either way, the value will be cast based on its schema type before being set during document creation.Example:
// values are cast: var schema = new Schema({ aNumber: Number, default: "4.815162342" }) var M = db.model('M', schema) var m = new M; console.log(m.aNumber) // 4.815162342 // default unique objects for Mixed types: var schema = new Schema({ mixed: Schema.Types.Mixed }); schema.path('mixed').default(function () { return {}; }); // if we don't use a function to return object literals for Mixed defaults, // each document will receive a reference to the same object literal creating // a "shared" object instance: var schema = new Schema({ mixed: Schema.Types.Mixed }); schema.path('mixed').default({}); var M = db.model('M', schema); var m1 = new M; m1.mixed.added = 1; console.log(m1.mixed); // { added: 1 } var m2 = new M; console.log(m2.mixed); // { added: 1 }
SchemaType#index(
options
)Declares the index options for this schematype.
show codeSchemaType.prototype.index = function (options) { this._index = options; utils.expires(this._index); return this; };
Returns:
- <SchemaType> this
Example:
var s = new Schema({ name: { type: String, index: true }) var s = new Schema({ name: { type: String, index: { unique: true, expires: '1d' }}) Schema.path('my.path').index(true); Schema.path('my.path').index({ expires: 60 }); Schema.path('my.path').index({ unique: true, sparse: true });
NOTE:
Indexes are created in the background by default. Specify
background: false
to override.SchemaType#unique(
bool
)Declares an unique index.
show codeSchemaType.prototype.unique = function (bool) { if (!this._index || 'Object' !== this._index.constructor.name) { this._index = {}; } this._index.unique = bool; return this; };
Parameters:
bool
<Boolean>
Returns:
- <SchemaType> this
Examples:
var s = new Schema({ name: { type: String, unique: true }) Schema.path('name').index({ unique: true });
SchemaType#sparse(
bool
)Declares a sparse index.
show codeSchemaType.prototype.sparse = function (bool) { if (!this._index || 'Object' !== this._index.constructor.name) { this._index = {}; } this._index.sparse = bool; return this; };
Parameters:
bool
<Boolean>
Returns:
- <SchemaType> this
Examples:
var s = new Schema({ name: { type: String, sparse: true }) Schema.path('name').index({ sparse: true });
SchemaType#expires(
when
)Declares a TTL index (rounded to the nearest second) for Date types only.
show codeSchemaType.prototype.expires = function (when) { if (!this._index || 'Object' !== this._index.constructor.name) { this._index = {}; } this._index.expires = when; utils.expires(this._index); return this; };
Returns:
- <SchemaType> this
This sets the
expiresAfterSeconds
index option available in MongoDB >= 2.1.2.
This index type is only compatible with Date types.Example:
// expire in 24 hours new Schema({..}, { expires: 60*60*24 });
expires
utilizes thems
module from guille allowing us to use a friendlier syntax:Example:
// expire in 24 hours new Schema({..}, { expires: '24h' }); // expire in 1.5 hours new Schema({..}, { expires: '1.5h' }); // expire in 7 days var schema = new Schema({..}); schema.expires('7d');
SchemaType#set(
fn
)Adds a setter to this schematype.
show codeSchemaType.prototype.set = function (fn) { if ('function' != typeof fn) throw new Error('A setter must be a function.'); this.setters.push(fn); return this; };
Parameters:
fn
<Function>
Returns:
- <SchemaType> this
Example:
function capitalize (val) { if ('string' != typeof val) val = ''; return val.charAt(0).toUpperCase() + val.substring(1); } var s = new Schema({ name: { type: String, set: capitalize }) // or Schema.path('name').set(capitalize);
SchemaType#get(
fn
)Adds a getter to this schematype.
show codeSchemaType.prototype.get = function (fn) { if ('function' != typeof fn) throw new Error('A getter must be a function.'); this.getters.push(fn); return this; };
Parameters:
fn
<Function>
Returns:
- <SchemaType> this
Example:
function dob (val) { if (!val) return val; return (val.getMonth() + 1) + "/" + val.getDate() + "/" + val.getFullYear(); } var s = new Schema({ born: { type: Date, get: dob }) // or Schema.path('name').get(dob);
SchemaType#validate(
obj
,[error]
)Adds validator(s) for this document path.
show codeSchemaType.prototype.validate = function (obj, error) { if ('function' == typeof obj || obj && 'RegExp' === obj.constructor.name) { this.validators.push([obj, error]); return this; } var i = arguments.length , arg while (i--) { arg = arguments[i]; if (!(arg && 'Object' == arg.constructor.name)) { var msg = 'Invalid validator. Received (' + typeof arg + ') ' + arg + '. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate'; throw new Error(msg); } this.validate(arg.validator, arg.msg); } return this; };
Validators must return
Boolean
. Returning false is interpreted as validation failure.Examples:
function validator () { ... } var single = [validator, 'failed'] new Schema({ name: { type: String, validate: single }}); var many = [ { validator: validator, msg: 'uh oh' } , { validator: fn, msg: 'failed' } ] new Schema({ name: { type: String, validate: many }}); // or utilizing SchemaType methods directly: var schema = new Schema({ name: 'string' }); schema.path('name').validate(validator, 'validation failed');
Asynchronous validation:
Passing a validator function that receives two arguments tells mongoose that the validator is an asynchronous validator. The first arg passed is the value to validate, the second is an callback function that must be passed either
true
orfalse
when validation is complete. Asynchronous validators open the door for retreiving other documents from the database first to validate against.schema.path('name').validate(function (value, respond) { doStuff(value, function () { ... respond(false); // validation failed }) }, 'my error type');
Validation occurs
pre('save')
or whenever you manually execute document#validate.If validation fails during
pre('save')
and no callback was passed to receive the error, anerror
event will be emitted on your Models associated db connection, passing the validation error object along.var conn = mongoose.createConnection(..); conn.on('error', handleError); var Product = conn.model('Product', yourSchema); var dvd = new Product(..); dvd.save(); // emits error on the `conn` above
If you desire handling these errors at the Model level, attach an
error
listener to your Model and the event will instead be emitted there.// registering an error listener on the Model lets us handle errors more locally Product.on('error', handleError);
SchemaType#required(
required
)Adds a required validator to this schematype.
show codeSchemaType.prototype.required = function (required) { var self = this; function __checkRequired (v) { // in here, `this` refers to the validating document. // no validation when this path wasn't selected in the query. if ('isSelected' in this && !this.isSelected(self.path) && !this.isModified(self.path)) return true; return self.checkRequired(v); } if (false === required) { this.isRequired = false; this.validators = this.validators.filter(function (v) { return v[0].name !== '__checkRequired'; }); } else { this.isRequired = true; this.validators.push([__checkRequired, 'required']); } return this; };
Parameters:
required
<Boolean> enable/disable the validator
Returns:
- <SchemaType> this
Example:
var s = new Schema({ born: { type: Date, required: true }) // or Schema.path('name').required(true);
SchemaType#getDefault(
scope
,init
)Gets the default value
show codeSchemaType.prototype.getDefault = function (scope, init) { var ret = 'function' === typeof this.defaultValue ? this.defaultValue.call(scope) : this.defaultValue; if (null !== ret && undefined !== ret) { return this.cast(ret, scope, init); } else { return ret; } };
SchemaType#applySetters(
value
,scope
,init
)Applies setters
show codeSchemaType.prototype.applySetters = function (value, scope, init, priorVal) { if (SchemaType._isRef(this, value, init)) return value; var v = value , setters = this.setters , len = setters.length if (!len) { if (null === v || undefined === v) return v; return init ? v // if we just initialized we dont recast : this.cast(v, scope, init, priorVal) } while (len--) { v = setters[len].call(scope, v, this); } if (null === v || undefined === v) return v; // do not cast until all setters are applied #665 v = this.cast(v, scope, init, priorVal); return v; };
SchemaType#applyGetters(
value
,scope
)Applies getters to a value
show codeSchemaType.prototype.applyGetters = function (value, scope) { if (SchemaType._isRef(this, value, true)) return value; var v = value , getters = this.getters , len = getters.length; if (!len) { return v; } while (len--) { v = getters[len].call(scope, v, this); } return v; };
SchemaType#select(
val
)Sets default
show codeselect()
behavior for this path.SchemaType.prototype.select = function select (val) { this.selected = !! val; }
Parameters:
val
<Boolean>
Set to
true
if this path should always be included in the results,false
if it should be excluded by default. This setting can be overridden at the query level.Example:
T = db.model('T', new Schema({ x: { type: String, select: true }})); T.find(..); // field x will always be selected .. // .. unless overridden; T.find().select('-x').exec(callback);
SchemaType#doValidate(
value
,callback
,scope
)Performs a validation of
show codevalue
using the validators declared for this SchemaType.SchemaType.prototype.doValidate = function (value, fn, scope) { var err = false , path = this.path , count = this.validators.length; if (!count) return fn(null); function validate (val, msg) { if (err) return; if (val === undefined || val) { --count || fn(null); } else { fn(err = new ValidatorError(path, msg)); } } this.validators.forEach(function (v) { var validator = v[0] , message = v[1]; if (validator instanceof RegExp) { validate(validator.test(value), message); } else if ('function' === typeof validator) { if (2 === validator.length) { validator.call(scope, value, function (val) { validate(val, message); }); } else { validate(validator.call(scope, value), message); } } }); };
SchemaType._isRef(
self
,value
,init
)Determines if value is a valid Reference.
show codeSchemaType._isRef = function (self, value, init) { if (init && self.options && self.options.ref) { if (null == value) return true; if (value._id && value._id.constructor.name === self.instance) return true; } return false; }
Parameters:
self
<SchemaType>value
<Object>init
<Boolean>
Returns:
- <Boolean>
- types/array.js
MongooseArray(
values
,path
,doc
)Mongoose Array constructor.
show codefunction MongooseArray (values, path, doc) { var arr = []; arr.push.apply(arr, values); arr.__proto__ = MongooseArray.prototype; arr._atomics = {}; arr.validators = []; arr._path = path; if (doc) { arr._parent = doc; arr._schema = doc.schema.path(path); } return arr; };
Inherits:
NOTE:
Values always have to be passed to the constructor to initialize, otherwise
MongooseArray#push
will mark the array as modified.MongooseArray#_cast(
value
)Casts a member based on this arrays schema.
show codeMongooseArray.prototype._cast = function (value) { var cast = this._schema.caster.cast , doc = this._parent; return cast.call(null, value, doc); };
Parameters:
value
<any>
Returns:
- <value> the casted value
MongooseArray#_markModified(
embeddedDoc
,embeddedPath
)Marks this array as modified.
show codeMongooseArray.prototype._markModified = function (embeddedDoc, embeddedPath) { var parent = this._parent , dirtyPath; if (parent) { if (arguments.length) { // If an embedded doc bubbled up the change dirtyPath = [this._path, this.indexOf(embeddedDoc), embeddedPath].join('.'); } else { dirtyPath = this._path; } parent.markModified(dirtyPath); } return this; };
Parameters:
embeddedDoc
<EmbeddedDocument> the embedded doc that invoked this method on the ArrayembeddedPath
<String> the path which changed in the embeddedDoc
If it bubbles up from an embedded document change, then it takes the following arguments (otherwise, takes 0 arguments)
MongooseArray#_registerAtomic(
op
,val
)Register an atomic operation with the parent.
show codeMongooseArray.prototype._registerAtomic = function (op, val) { if ('$set' == op) { // $set takes precedence over all other ops. // mark entire array modified. this._atomics = { $set: val }; this._markModified(); return this; } var atomics = this._atomics; // reset pop/shift after save if ('$pop' == op && !('$pop' in atomics)) { var self = this; this._parent.once('save', function () { self._popped = self._shifted = null; }); } if (this._atomics.$set) { return this; } // check for impossible $atomic combos (Mongo denies more than one // $atomic op on a single path if (Object.keys(atomics).length && !(op in atomics)) { // a different op was previously registered. // save the entire thing. this._atomics = { $set: this }; this._markModified(); return this; } if (op === '$pullAll' || op === '$pushAll' || op === '$addToSet') { atomics[op] || (atomics[op] = []); atomics[op] = atomics[op].concat(val); } else if (op === '$pullDocs') { var pullOp = atomics['$pull'] || (atomics['$pull'] = {}) , selector = pullOp['_id'] || (pullOp['_id'] = {'$in' : [] }); selector['$in'] = selector['$in'].concat(val); } else { atomics[op] = val; } this._markModified(); return this; };
MongooseArray#hasAtomics()
Returns the number of pending atomic operations to send to the db for this array.
show codeMongooseArray.prototype.hasAtomics = function hasAtomics () { if (!(this._atomics && 'Object' === this._atomics.constructor.name)) { return 0; } return Object.keys(this._atomics).length; }
Returns:
- <Number>
MongooseArray#push(
[args...]
)Wraps
show codeArray#push
with proper change tracking.MongooseArray.prototype.push = function () { var values = [].map.call(arguments, this._cast, this) , ret = [].push.apply(this, values); // $pushAll might be fibbed (could be $push). But it makes it easier to // handle what could have been $push, $pushAll combos this._registerAtomic('$pushAll', values); return ret; };
Parameters:
[args...]
<Object>
MongooseArray#nonAtomicPush(
[args...]
)Pushes items to the array non-atomically.
show codeMongooseArray.prototype.nonAtomicPush = function () { var values = [].map.call(arguments, this._cast, this) , ret = [].push.apply(this, values); this._registerAtomic('$set', this); return ret; };
Parameters:
[args...]
<any>
NOTE:
marks the entire array as modified, which if saved, will store it as a
$set
operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.MongooseArray#$pop()
Pops the array atomically at most one time per document
save()
.See:
NOTE:
Calling this mulitple times on an array before saving sends the same command as calling it once.
This update is implemented using the MongoDB $pop method which enforces this restriction.doc.array = [1,2,3]; var popped = doc.array.$pop(); console.log(popped); // 3 console.log(doc.array); // [1,2] // no affect popped = doc.array.$pop(); console.log(doc.array); // [1,2] doc.save(function (err) { if (err) return handleError(err); // we saved, now $pop works again popped = doc.array.$pop(); console.log(popped); // 2 console.log(doc.array); // [1] })
MongooseArray#pop()
Wraps
show codeArray#pop
with proper change tracking.MongooseArray.prototype.pop = function () { var ret = [].pop.call(this); this._registerAtomic('$set', this); return ret; };
Note:
marks the entire array as modified which will pass the entire thing to $set potentially overwritting any changes that happen between when you retrieved the object and when you save it.
MongooseArray#$shift()
Atomically shifts the array at most one time per document
save()
.See:
NOTE:
Calling this mulitple times on an array before saving sends the same command as calling it once.
This update is implemented using the MongoDB $pop method which enforces this restriction.doc.array = [1,2,3]; var shifted = doc.array.$shift(); console.log(shifted); // 1 console.log(doc.array); // [2,3] // no affect shifted = doc.array.$shift(); console.log(doc.array); // [2,3] doc.save(function (err) { if (err) return handleError(err); // we saved, now $shift works again shifted = doc.array.$shift(); console.log(shifted ); // 2 console.log(doc.array); // [3] })
MongooseArray#shift()
Wraps
show codeArray#shift
with proper change tracking.MongooseArray.prototype.shift = function () { var ret = [].shift.call(this); this._registerAtomic('$set', this); return ret; };
Example:
doc.array = [2,3]; var res = doc.array.shift(); console.log(res) // 2 console.log(doc.array) // [3]
Note:
marks the entire array as modified, which if saved, will store it as a
$set
operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.MongooseArray#remove(
[args...]
)Removes items from an array atomically
show codeMongooseArray.prototype.remove = function () { var args = [].map.call(arguments, this._cast, this); if (args.length == 1) this.pull(args[0]); else this.pull.apply(this, args); return args; };
Parameters:
[args...]
<Object> values to remove
See:
Examples:
doc.array.remove(ObjectId) doc.array.remove('tag 1', 'tag 2')
MongooseArray#pull(
[args...]
)Pulls items from the array atomically.
show codeMongooseArray.prototype.pull = function () { var values = [].map.call(arguments, this._cast, this) , cur = this._parent.get(this._path) , i = cur.length , mem; while (i--) { mem = cur[i]; if (mem instanceof EmbeddedDocument) { if (values.some(function (v) { return v.equals(mem); } )) { [].splice.call(cur, i, 1); } } else if (~cur.indexOf.call(values, mem)) { [].splice.call(cur, i, 1); } } if (values[0] instanceof EmbeddedDocument) { this._registerAtomic('$pullDocs', values.map( function (v) { return v._id; } )); } else { this._registerAtomic('$pullAll', values); } return this; };
Parameters:
[args...]
<any>
See:
MongooseArray#splice()
Wraps
show codeArray#splice
with proper change tracking.MongooseArray.prototype.splice = function () { if (arguments.length) { var ret = [].splice.apply(this, arguments); this._registerAtomic('$set', this); } return ret; };
Note:
marks the entire array as modified, which if saved, will store it as a
$set
operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.MongooseArray#unshift()
Wraps
show codeArray#unshift
with proper change tracking.MongooseArray.prototype.unshift = function () { var values = [].map.call(arguments, this._cast, this); [].unshift.apply(this, values); this._registerAtomic('$set', this); return this.length; };
Note:
marks the entire array as modified, which if saved, will store it as a
$set
operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.MongooseArray#sort()
Wraps
show codeArray#sort
with proper change tracking.MongooseArray.prototype.sort = function () { var ret = [].sort.apply(this, arguments); this._registerAtomic('$set', this); return ret; }
NOTE:
marks the entire array as modified, which if saved, will store it as a
$set
operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.MongooseArray#addToSet(
[args...]
)Adds values to the array if not already present.
show codeMongooseArray.prototype.addToSet = function addToSet () { var values = [].map.call(arguments, this._cast, this) , added = [] , type = values[0] instanceof EmbeddedDocument ? 'doc' : values[0] instanceof Date ? 'date' : ''; values.forEach(function (v) { var found; switch (type) { case 'doc': found = this.some(function(doc){ return doc.equals(v) }); break; case 'date': var val = +v; found = this.some(function(d){ return +d === val }); break; default: found = ~this.indexOf(v); } if (!found) { [].push.call(this, v); this._registerAtomic('$addToSet', v); [].push.call(added, v); } }, this); return added; };
Parameters:
[args...]
<any>
Returns:
- <Array> the values that were added
Example:
console.log(doc.array) // [2,3,4] var added = doc.array.addToSet(4,5); console.log(doc.array) // [2,3,4,5] console.log(added) // [5]
MongooseArray#toObject(
options
)Returns a native js Array.
show codeMongooseArray.prototype.toObject = function (options) { if (options && options.depopulate && this[0] instanceof Document) { return this.map(function (doc) { return doc._id; }); } // return this.slice()? return this.map(function (doc) { return doc; }); };
Parameters:
options
<Object>
Returns:
- <Array>
MongooseArray#inspect()
Helper for console.log
show codeMongooseArray.prototype.inspect = function () { return '[' + this.map(function (doc) { return ' ' + doc; }) + ' ]'; };
MongooseArray#indexOf(
obj
)Return the index of
show codeobj
or-1
if not found.MongooseArray.prototype.indexOf = function indexOf (obj) { if (obj instanceof ObjectId) obj = obj.toString(); for (var i = 0, len = this.length; i < len; ++i) { if (obj == this[i]) return i; } return -1; };
Parameters:
obj
<Object> the item to look for
Returns:
- <Number>
- types/buffer.js
MongooseBuffer(
value
,encode
,offset
)Mongoose Buffer constructor.
show codefunction MongooseBuffer (value, encode, offset) { var length = arguments.length; var val; if (0 === length || null === arguments[0] || undefined === arguments[0]) { val = 0; } else { val = value; } var encoding; var path; var doc; if (Array.isArray(encode)) { // internal casting path = encode[0]; doc = encode[1]; } else { encoding = encode; } var buf = new Buffer(val, encoding, offset); buf.__proto__ = MongooseBuffer.prototype; // make sure these internal props don't show up in Object.keys() Object.defineProperties(buf, { validators: { value: [] } , _path: { value: path } , _parent: { value: doc } }); if (doc && "string" === typeof path) { Object.defineProperty(buf, '_schema', { value: doc.schema.path(path) }); } return buf; };
Inherits:
Values always have to be passed to the constructor to initialize.
MongooseBuffer#_markModified()
Marks this buffer as modified.
show codeMongooseBuffer.prototype._markModified = function () { var parent = this._parent; if (parent) { parent.markModified(this._path); } return this; };
MongooseBuffer#write()
Writes the buffer.
show codeMongooseBuffer.prototype.write = function () { var written = Buffer.prototype.write.apply(this, arguments); if (written > 0) { this._markModified(); } return written; };
MongooseBuffer#copy(
target
)Copies the buffer.
show codeMongooseBuffer.prototype.copy = function (target) { var ret = Buffer.prototype.copy.apply(this, arguments); if (target instanceof MongooseBuffer) { target._markModified(); } return ret; };
Parameters:
target
<Buffer>
Returns:
Note:
Buffer#copy
does not marktarget
as modified so you must copy from aMongooseBuffer
for it to work as expected. This is a work around sincecopy
modifies the target, not this.MongooseBuffer#toObject(
[subtype]
)Converts this buffer to its Binary type representation.
show codeMongooseBuffer.prototype.toObject = function (subtype) { subtype = typeof subtype !== 'undefined' ? subtype : 0x00 return new Binary(this, subtype); };
Parameters:
[subtype]
<Hex>
Returns:
- <Binary>
SubTypes:
- 0x00: Binary/Generic
- 0x01: Function
- 0x02: Binary (Deprecated, 0x00 is new default)
- 0x03: UUID
- 0x04: MD5
- 0x80: User Defined
- types/documentarray.js
MongooseDocumentArray(
values
,path
,doc
)DocumentArray constructor
show codefunction MongooseDocumentArray (values, path, doc) { var arr = []; // Values always have to be passed to the constructor to initialize, since // otherwise MongooseArray#push will mark the array as modified to the parent. arr.push.apply(arr, values); arr.__proto__ = MongooseDocumentArray.prototype; arr._atomics = {}; arr.validators = []; arr._path = path; if (doc) { arr._parent = doc; arr._schema = doc.schema.path(path); doc.on('save', arr.notify('save')); doc.on('isNew', arr.notify('isNew')); } return arr; };
Returns:
Inherits:
MongooseDocumentArray#_cast()
Overrides MongooseArray#cast
show codeMongooseDocumentArray.prototype._cast = function (value) { var doc = new this._schema.casterConstructor(value, this); return doc; };
MongooseDocumentArray#id(
id
)Searches array items for the first document with a matching id.
show codeMongooseDocumentArray.prototype.id = function (id) { var casted , _id; try { casted = ObjectId.toString(ObjectIdSchema.prototype.cast.call({}, id)); } catch (e) { casted = null; } for (var i = 0, l = this.length; i < l; i++) { _id = this[i].get('_id'); if (!(_id instanceof ObjectId)) { if (String(id) == _id) return this[i]; } else { if (casted == _id) return this[i]; } } return null; };
Returns:
- <EmbeddedDocument, null> the subdocuent or null if not found.
Example:
var embeddedDoc = m.array.id(some_id);
MongooseDocumentArray#toObject()
Returns a native js Array of plain js objects
show codeMongooseDocumentArray.prototype.toObject = function () { return this.map(function (doc) { return doc && doc.toObject() || null; }); };
Returns:
- <Array>
NOTE:
Each sub-document is converted to a plain object by calling its
#toObject
method.MongooseDocumentArray#inspect()
Helper for console.log
show codeMongooseDocumentArray.prototype.inspect = function () { return '[' + this.map(function (doc) { if (doc) { return doc.inspect ? doc.inspect() : util.inspect(doc) } return 'null' }).join(' ') + ']'; };
MongooseDocumentArray#create(
obj
)Creates a subdocument casted to this schema.
show codeMongooseDocumentArray.prototype.create = function (obj) { return new this._schema.casterConstructor(obj); }
Parameters:
obj
<Object> the value to cast to this arrays SubDocument schema
This is the same subdocument constructor used for casting.
MongooseDocumentArray#notify(
event
)Creates a fn that notifies all child docs of
show codeevent
.MongooseDocumentArray.prototype.notify = function notify (event) { var self = this; return function notify (val) { var i = self.length; while (i--) { self[i].emit(event, val); } } }
Parameters:
event
<String>
Returns:
- <Function>
- types/embedded.js
EmbeddedDocument(
obj
,parentArr
,skipId
)EmbeddedDocument constructor.
show codefunction EmbeddedDocument (obj, parentArr, skipId) { if (parentArr) { this.__parentArray = parentArr; this.__parent = parentArr._parent; } else { this.__parentArray = undefined; this.__parent = undefined; } Document.call(this, obj, undefined, skipId); var self = this; this.on('isNew', function (val) { self.isNew = val; }); };
Parameters:
obj
<Object> js object returned from the dbparentArr
<MongooseDocumentArray> the parent array of this documentskipId
<Boolean>
Inherits:
EmbeddedDocument#markModified(
path
)Marks the embedded doc modified.
show codeEmbeddedDocument.prototype.markModified = function (path) { if (!this.__parentArray) return; this._activePaths.modify(path); if (this.isNew) { // Mark the WHOLE parent array as modified // if this is a new document (i.e., we are initializing // a document), this.__parentArray._markModified(); } else this.__parentArray._markModified(this, path); };
Parameters:
path
<String> the path which changed
Example:
var doc = blogpost.comments.id(hexstring); doc.mixed.type = 'changed'; doc.markModified('mixed.type');
EmbeddedDocument#save(
[fn]
)Used as a stub for hooks.js
show codeEmbeddedDocument.prototype.save = function(fn) { if (fn) fn(null); return this; };
Parameters:
[fn]
<Function>
Returns:
- <EmbeddedDocument> this
NOTE:
This is a no-op. Does not actually save the doc to the db.
EmbeddedDocument#remove(
[fn]
)Removes the subdocument from its parent array.
show codeEmbeddedDocument.prototype.remove = function (fn) { if (!this.__parentArray) return this; var _id; if (!this.willRemove) { _id = this._doc._id; if (!_id) { throw new Error('For your own good, Mongoose does not know ' + 'how to remove an EmbeddedDocument that has no _id'); } this.__parentArray.pull({ _id: _id }); this.willRemove = true; } if (fn) fn(null); return this; };
Parameters:
[fn]
<Function>
EmbeddedDocument#update()
Override #update method of parent documents.
show codeEmbeddedDocument.prototype.update = function () { throw new Error('The #update method is not available on EmbeddedDocuments'); }
EmbeddedDocument#inspect()
Helper for console.log
show codeEmbeddedDocument.prototype.inspect = function () { return inspect(this.toObject()); };
EmbeddedDocument#invalidate(
path
,err
)Marks a path as invalid, causing validation to fail.
show codeEmbeddedDocument.prototype.invalidate = function (path, err, first) { if (!this.__parent) return false; var index = this.__parentArray.indexOf(this); var parentPath = this.__parentArray._path; var fullPath = [parentPath, index, path].join('.'); this.__parent.invalidate(fullPath, err); if (first) this._validationError = ownerDocument(this)._validationError; return true; }
Parameters:
Returns:
- <Boolean>
EmbeddedDocument#ownerDocument()
Returns the top level document of this sub-document.
show codeEmbeddedDocument.prototype.ownerDocument = function () { return ownerDocument(this); }
Returns:
- <Document>
EmbeddedDocument#parent()
Returns this sub-documents parent document.
show codeEmbeddedDocument.prototype.parent = function () { return this.__parent; }
EmbeddedDocument#parentArray()
Returns this sub-documents parent array.
show codeEmbeddedDocument.prototype.parentArray = function () { return this.__parentArray; }
- types/objectid.js
ObjectId.fromString(
str
)Creates an ObjectId from
show codestr
ObjectId.fromString;
Returns:
- <ObjectId>
ObjectId.toString(
oid
)Converts
show codeoid
to a string.ObjectId.toString;
Parameters:
oid
<ObjectId> ObjectId instance
Returns:
- <String>
- utils.js
exports.toCollectionName(
name
)Produces a collection name from model
show codename
.exports.toCollectionName = function (name) { if ('system.profile' === name) return name; if ('system.indexes' === name) return name; return pluralize(name.toLowerCase()); };
Parameters:
name
<String> a model name
Returns:
- <String> a collection name
exports.pluralization
Pluralization rules.
show codeexports.pluralization = [ [/(m)an$/gi, '$1en'], [/(pe)rson$/gi, '$1ople'], [/(child)$/gi, '$1ren'], [/^(ox)$/gi, '$1en'], [/(ax|test)is$/gi, '$1es'], [/(octop|vir)us$/gi, '$1i'], [/(alias|status)$/gi, '$1es'], [/(bu)s$/gi, '$1ses'], [/(buffal|tomat|potat)o$/gi, '$1oes'], [/([ti])um$/gi, '$1a'], [/sis$/gi, 'ses'], [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'], [/(hive)$/gi, '$1s'], [/([^aeiouy]|qu)y$/gi, '$1ies'], [/(x|ch|ss|sh)$/gi, '$1es'], [/(matr|vert|ind)ix|ex$/gi, '$1ices'], [/([m|l])ouse$/gi, '$1ice'], [/(quiz)$/gi, '$1zes'], [/s$/gi, 's'], [/$/gi, 's'] ]; var rules = exports.pluralization;
These rules are applied while processing the argument to
toCollectionName
.exports.uncountables
Uncountable words.
show codeexports.uncountables = [ 'advice', 'energy', 'excretion', 'digestion', 'cooperation', 'health', 'justice', 'labour', 'machinery', 'equipment', 'information', 'pollution', 'sewage', 'paper', 'money', 'species', 'series', 'rain', 'rice', 'fish', 'sheep', 'moose', 'deer', 'news' ]; var uncountables = exports.uncountables;
These words are applied while processing the argument to
toCollectionName
.exports.deepEqual(
a
,b
)Determines if
show codea
andb
are deep equal.exports.deepEqual = function deepEqual (a, b) { if (a === b) return true; if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime(); if (a instanceof ObjectId && b instanceof ObjectId) { return a.toString() === b.toString(); } if (typeof a !== 'object' && typeof b !== 'object') return a == b; if (a === null || b === null || a === undefined || b === undefined) return false if (a.prototype !== b.prototype) return false; // Handle MongooseNumbers if (a instanceof Number && b instanceof Number) { return a.valueOf() === b.valueOf(); } if (Buffer.isBuffer(a)) { if (!Buffer.isBuffer(b)) return false; if (a.length !== b.length) return false; for (var i = 0, len = a.length; i < len; ++i) { if (a[i] !== b[i]) return false; } return true; } if (isMongooseObject(a)) a = a.toObject(); if (isMongooseObject(b)) b = b.toObject(); try { var ka = Object.keys(a), kb = Object.keys(b), key, i; } catch (e) {//happens when one is a string literal and the other isn't return false; } // having the same number of owned properties (keys incorporates // hasOwnProperty) if (ka.length != kb.length) return false; //the same set of keys (although not necessarily the same order), ka.sort(); kb.sort(); //~~~cheap key test for (i = ka.length - 1; i >= 0; i--) { if (ka[i] != kb[i]) return false; } //equivalent values for every corresponding key, and //~~~possibly expensive deep test for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; if (!deepEqual(a[key], b[key])) return false; } return true; };
Returns:
- <Boolean>
Modified from node/lib/assert.js
exports.clone(
obj
,options
)Object clone with Mongoose natives support.
show codeexports.clone = function clone (obj, options) { if (obj === undefined || obj === null) return obj; if (Array.isArray(obj)) return cloneArray(obj, options); if (isMongooseObject(obj)) { if (options && options.json && 'function' === typeof obj.toJSON) { return obj.toJSON(options); } else { return obj.toObject(options); } } if ('Object' === obj.constructor.name) return cloneObject(obj, options); if ('Date' === obj.constructor.name || 'Function' === obj.constructor.name) return new obj.constructor(+obj); if ('RegExp' === obj.constructor.name) return new RegExp(obj.source); if (obj instanceof ObjectId) { return new ObjectId(obj.id); } if (obj.valueOf) return obj.valueOf(); }; var clone = exports.clone;
Returns:
- <Object> the cloned object
Creates a minimal data Object.
It does not clone empty Arrays, empty Objects, and undefined values.
This makes the data payload sent to MongoDB as minimal as possible.exports.options(
defaults
,options
)Copies and merges options with defaults.
show codeexports.options = function (defaults, options) { var keys = Object.keys(defaults) , i = keys.length , k ; options = options || {}; while (i--) { k = keys[i]; if (!(k in options)) { options[k] = defaults[k]; } } return options; };
Returns:
- <Object> the merged object
exports.random()
Generates a random string
show codeexports.random = function () { return Math.random().toString().substr(3); };
exports.merge(
to
,from
)Merges
show codefrom
intoto
without overwriting existing properties.exports.merge = function merge (to, from) { var keys = Object.keys(from) , i = keys.length , key while (i--) { key = keys[i]; if ('undefined' === typeof to[key]) { to[key] = from[key]; } else { merge(to[key], from[key]); } } };
exports.args()
A faster Array.prototype.slice.call(arguments) alternative
show codeexports.args = function (args, slice, sliceEnd) { var ret = []; var start = slice || 0; var end = 3 === arguments.length ? sliceEnd : args.length; for (var i = start; i < end; ++i) { ret[i - start] = args[i]; } return ret; }
exports.tick(
callback
)process.nextTick helper.
show codeexports.tick = function tick (callback) { if ('function' !== typeof callback) return; return function () { try { callback.apply(this, arguments); } catch (err) { // only nextTick on err to get out of // the event loop and avoid state corruption. process.nextTick(function () { throw err; }); } } }
Parameters:
callback
<Function>
Wraps
callback
in a try/catch + nextTick.node-mongodb-native has a habit of state corruption when an error is immediately thrown from within a collection callback.
exports.isMongooseObject(
v
)Returns if
show codev
is a mongoose object that has atoObject()
method we can use.exports.isMongooseObject = function (v) { Document || (Document = require('./document')); MongooseArray || (MongooseArray = require('./types').Array); MongooseBuffer || (MongooseBuffer = require('./types').Buffer); return v instanceof Document || v instanceof MongooseArray || v instanceof MongooseBuffer } var isMongooseObject = exports.isMongooseObject;
Parameters:
v
<any>
This is for compatibility with libs like Date.js which do foolish things to Natives.
exports.expires(
object
)Converts
show codeexpires
options of index objects toexpiresAfterSeconds
options for MongoDB.exports.expires = function expires (object) { if (!(object && 'Object' == object.constructor.name)) return; if (!('expires' in object)) return; var when; if ('string' != typeof object.expires) { when = object.expires; } else { when = Math.round(ms(object.expires) / 1000); } object.expiresAfterSeconds = when; delete object.expires; }
Parameters:
object
<Object>
- virtualtype.js
VirtualType()
VirtualType constructor
show codefunction VirtualType (options) { this.getters = []; this.setters = []; this.options = options || {}; }
This is what mongoose uses to define virtual attributes via
Schema.prototype.virtual
.Example:
var fullname = schema.virtual('fullname'); fullname instanceof mongoose.VirtualType // true
VirtualType#get(
fn
)Defines a getter.
show codeVirtualType.prototype.get = function (fn) { this.getters.push(fn); return this; };
Parameters:
fn
<Function>
Returns:
- <VirtualType> this
Example:
var virtual = schema.virtual('fullname'); virtual.get(function () { return this.name.first + ' ' + this.name.last; });
VirtualType#set(
fn
)Defines a setter.
show codeVirtualType.prototype.set = function (fn) { this.setters.push(fn); return this; };
Parameters:
fn
<Function>
Returns:
- <VirtualType> this
Example:
var virtual = schema.virtual('fullname'); virtual.set(function (v) { var parts = v.split(' '); this.name.first = parts[0]; this.name.last = parts[1]; });
VirtualType#applyGetters(
value
,scope
)Applies getters to
show codevalue
using optionalscope
.VirtualType.prototype.applyGetters = function (value, scope) { var v = value; for (var l = this.getters.length - 1; l >= 0; l--){ v = this.getters[l].call(scope, v); } return v; };
Returns:
- <any> the value after applying all getters
VirtualType#applySetters(
value
,scope
)Applies setters to
show codevalue
using optionalscope
.VirtualType.prototype.applySetters = function (value, scope) { var v = value; for (var l = this.setters.length - 1; l >= 0; l--){ this.setters[l].call(scope, v); } return v; };
Returns:
- <any> the value after applying all setters