MongooseExpressive MongoDB for Node.JS | |
| lib/collection.js |
Collection constructor
|
function Collection (name, conn) {
this.name = name;
this.conn = conn;
this.buffer = true;
this.queue = [];
if (this.conn.readyState == 1) this.onOpen();
};
|
The collection name
|
Collection.prototype.name;
|
The Connection instance
|
Collection.prototype.conn;
|
Module exports.
|
module.exports = Collection;
|
| lib/connection.js |
Module dependencies.
|
var url = require('url')
, utils = require('./utils')
, EventEmitter = utils.EventEmitter
, driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native'
, Model = require('./model')
, Schema = require('./schema')
, Collection = require(driver + '/collection');
|
Connection constructor. For practical reasons, a Connection equals a Db
|
function Connection (base) {
this.base = base;
this.collections = {};
this.models = {};
};
|
Inherit from EventEmitter.
|
Connection.prototype.__proto__ = EventEmitter.prototype;
|
Connection ready state:
0 = Disconnected
1 = Connected
2 = Connecting
3 = Disconnecting
|
Connection.prototype.readyState = 0;
|
A hash of the collections associated with this connection
|
Connection.prototype.collections;
|
The mongodb.Db instance, set when the connection is opened
|
Connection.prototype.db;
|
Establishes the connection
options is a hash with the following optional properties:
options.db - passed to the connection db instance
options.server - passed to the connection server instance(s)
options.replset - passed to the connection ReplSetServer instance
options.user - username for authentication
options.pass - password for authentication
Notes:
Mongoose forces the db option forceServerObjectId false and cannot
be overridden.
Mongoose defaults the server auto_reconnect options to true which
can be overridden.
See the node-mongodb-native driver instance for options that it
understands.
|
Connection.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;
}
uri = url.parse(host);
host = uri.hostname;
port = uri.port || 27017;
database = uri.pathname && uri.pathname.replace(/\//g, '');
}
callback = callback || noop;
this.options = this.defaultOptions(options);
if (0 !== this.readyState) {
var err = new Error('Trying to open unclosed connection.');
err.state = this.readyState;
callback(err);
return this;
}
if (!host) {
callback(new Error('Missing connection hostname.'));
return this;
}
if (!database) {
callback(new Error('Missing connection database.'));
return this;
}
if (uri && uri.auth) {
var auth = uri.auth.split(':');
this.user = auth[0];
this.pass = auth[1];
} 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];
} 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.readyState = 2;
this.emit('opening');
this.doOpen(function (err) {
if (err) {
self.readyState = 0;
if (self._events && self._events.error &&
('function' == typeof self._events.error || self._events.error.length)) {
self.emit("error", err);
}
} else {
self.onOpen();
}
callback(err || null);
});
return this;
};
|
Connects to a replica set.
Supply a comma-separted list of mongodb:// URIs. You only need to specify
the database name and/or auth to one of them.
The options parameter is passed to the low level connection. See the
node-mongodb-native driver instance for detail.
param: String comma-separated mongodb:// URIs param: String optional database name param: Object optional options param: Function optional callback
|
Connection.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);
callback = callback || noop;
if (uris.length < 2) {
callback(new Error('Please provide comma-separated URIs'));
return this;
}
this.host = [];
this.port = [];
uris.forEach(function (uri) {
var uri = url.parse(uri);
self.host.push(uri.hostname);
self.port.push(uri.port || 27017);
if (!self.name && 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) {
callback(new Error('No database name provided for replica set'));
return this;
}
this.readyState = 2;
this.emit('opening');
this.doOpenSet(function (err) {
if (err) {
if (self._events && self._events.error && self._events.error.length) {
self.emit("error", err);
}
self.readyState = 0;
} else {
self.onOpen();
}
callback(err || null);
});
};
|
Closes the connection
|
Connection.prototype.close = function (callback) {
var self = this
, callback = callback || function(){};
switch (this.readyState){
case 0:
callback(null);
break;
case 1:
this.readyState = 3;
this.doClose(function(err){
if (err){
callback(err);
} else {
self.onClose();
callback(null);
}
});
break;
case 2:
this.once('open', function(){
self.close(callback);
});
break;
case 3:
this.once('close', function () {
callback(null);
});
break;
}
return this;
};
|
Retrieves a collection, creating it if not cached.
|
Connection.prototype.collection = function (name) {
if (!(name in this.collections))
this.collections[name] = new Collection(name, this);
return this.collections[name];
};
|
Defines a model or retrieves it
|
Connection.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) {
Model = function Model () {
model.apply(this, arguments);
};
Model.__proto__ = model;
Model.prototype.__proto__ = model.prototype;
Model.prototype.db = this;
if ('string' === typeof schema) {
collection = schema;
}
if (!collection) {
collection = model.prototype.schema.set('collection') || utils.toCollectionName(name);
}
Model.prototype.collection = this.collection(collection);
Model.init();
}
this.models[name] = Model || model;
}
return this.models[name];
};
|
Set profiling level.
param: Int | String level - Either off (0), slow (1), or all (2) param: Int [ms] If profiling level is set to 1, this determines the threshold in milliseconds above which queries
will be logged. Defaults to 100. (optional)
param: Function callback api: public
|
Connection.prototype.setProfiling = function (level, ms, callback) {
if (1 !== 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);
});
};
|
Noop.
|
function noop () {}
|
Module exports.
|
module.exports = Connection;
|
| lib/document.js |
Module dependencies.
|
var EventEmitter = require('events').EventEmitter
, MongooseError = require('./error')
, MixedSchema = require('./schema/mixed')
, Schema = require('./schema')
, ValidatorError = require('./schematype').ValidatorError
, utils = require('./utils')
, clone = utils.clone
, isMongooseObject = utils.isMongooseObject
, inspect = require('util').inspect
, StateMachine = require('./statemachine')
, ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default')
, deepEqual = utils.deepEqual
, hooks = require('hooks')
, DocumentArray
|
Inherit from EventEmitter.
|
Document.prototype.__proto__ = EventEmitter.prototype;
|
Base Mongoose instance for the model. Set by the Mongoose instance upon
pre-compilation.
|
Document.prototype.base;
|
Document schema as a nested structure.
|
Document.prototype.schema;
|
Whether the document is new.
|
Document.prototype.isNew;
|
Validation errors.
|
Document.prototype.errors;
|
Sets a path, or many paths
Examples
// path, value
doc.set(path, value)
// object
doc.set({
path : value
, path2 : {
path : value
}
}
param: String | Object key path, or object param: Object value, or undefined or a prefix if first parameter is an object para: m
@optional {Schema|String|...} specify a type if this is an on-the-fly attribute api: public
|
Document.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) {
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 (undefined !== path[key]) {
this.set(prefix + key, path[key], constructing);
}
}
return this;
}
}
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('.')
, obj = this._doc
, self = this
, pathToMark
, subpaths
, subpath
if (parts.length <= 1) {
pathToMark = path;
} else {
subpaths = parts.map(function (part, i) {
return parts.slice(0, i).concat(part).join('.');
});
for (var i = 0, l = subpaths.length; i < l; i++) {
subpath = subpaths[i];
if (this.isDirectModified(subpath)
|| this.get(subpath) === null) {
pathToMark = subpath;
break;
}
}
if (!pathToMark) pathToMark = path;
}
if ((!schema || null === val || undefined === val) ||
this.try(function(){
var cur = constructing ? undefined : self.get(path);
var casted = schema.cast(val, self, false, cur);
val = schema.applySetters(casted, self);
})) {
if (this.isNew) {
this.markModified(pathToMark);
} else {
var priorVal = this.get(path);
if (!this.isDirectModified(pathToMark)) {
if (undefined === val && !this.isSelected(path)) {
this.markModified(pathToMark);
} else if (!deepEqual(val, priorVal)) {
this.markModified(pathToMark);
} else if (!constructing &&
null != val &&
path in this._activePaths.states.default &&
deepEqual(val, schema.getDefault(this, constructing))) {
this.markModified(pathToMark);
}
}
}
for (var i = 0, l = parts.length; 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]] = {};
}
}
}
}
return this;
};
|
Triggers casting on a specific path
|
Document.prototype.doCast = function (path) {
var schema = this.schema.path(path);
if (schema)
this.setValue(path, this.getValue(path));
};
|
Gets a path
|
Document.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;
};
|
Commits a path, marking as modified if needed. Useful for mixed keys
|
Document.prototype.markModified = function (path) {
this._activePaths.modify(path);
};
|
commit
Alias on markModified
|
Document.prototype.commit =
utils.dep('Document#commit'
, 'Document#markModified'
, Document.prototype.markModified);
|
Captures an exception that will be bubbled to save
|
Document.prototype.try = function (fn, scope) {
var res;
try {
fn.call(scope);
res = true;
} catch (e) {
this.error(e);
res = false;
}
return res;
};
|
modifiedPaths
Returns the list of paths that have been modified.
If we set documents.0.title to 'newTitle'
then documents , documents.0 , and documents.0.title
are modified.
api: public returns: Boolean
|
Document.prototype.__defineGetter__('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('.'));
}, []));
}, []);
});
|
Checks if a path or any full path containing path as part of
its path chain has been directly modified.
e.g., if we set documents.0.title to 'newTitle'
then we have directly modified documents.0.title
but not directly modified documents or documents.0 .
Nonetheless, we still say documents and documents.0
are modified. They just are not considered direct modified.
The distinction is important because we need to distinguish
between what has been directly modified and what hasn't so
that we can determine the MINIMUM set of dirty data
that we want to send to MongoDB on a Document save.
param: String path returns: Boolean api: public
|
Document.prototype.isModified = function (path) {
return !!~this.modifiedPaths.indexOf(path);
};
|
Checks if a path has been directly set and modified. False if
the path is only part of a larger path that was directly set.
e.g., if we set documents.0.title to 'newTitle'
then we have directly modified documents.0.title
but not directly modified documents or documents.0 .
Nonetheless, we still say documents and documents.0
are modified. They just are not considered direct modified.
The distinction is important because we need to distinguish
between what has been directly modified and what hasn't so
that we can determine the MINIMUM set of dirty data
that we want to send to MongoDB on a Document save.
param: String path returns: Boolean api: public
|
Document.prototype.isDirectModified = function (path) {
return (path in this._activePaths.states.modify);
};
|
Checks if a certain path was initialized
param: String path returns: Boolean api: public
|
Document.prototype.isInit = function (path) {
return (path in this._activePaths.states.init);
};
|
Checks if a path was selected.
##
param: String path return: Boolean api: public
|
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]) {
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;
while (i--) {
cur = paths[i];
if ('_id' == cur) continue;
if (0 === cur.indexOf(path + '.')) {
return inclusive;
}
if (0 === (path + '.').indexOf(cur)) {
return inclusive;
}
}
return ! inclusive;
}
return true;
}
|
Validation middleware
param: Function next api: public
|
Document.prototype.validate = function (next) {
var total = 0
, self = this
, validating = {}
if (!this._activePaths.some('require', 'init', 'modify')) {
return complete();
}
function complete () {
next(self._validationError);
self._validationError = null;
}
this._activePaths.forEach('require', 'init', 'modify', 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);
--total || complete();
}, self);
});
});
return this;
};
|
Marks a path as invalid, causing a subsequent validation to fail.
|
Document.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;
}
|
Returns if the document has been modified
return: Boolean api: public
|
Document.prototype.__defineGetter__('modified', function () {
return this._activePaths.some('modify');
});
|
Gets the document
Available options:
- getters: apply all getters (path and virtual getters)
- virtuals: apply virtual getters (can override
getters option)
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.prototype.toObject = function (options) {
options || (options = {});
options.minimize = true;
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;
};
|
JSON.stringify helper.
Implicitly called when a document is passed
to JSON.stringify()
return: Object api: public
|
Document.prototype.toJSON = function (options) {
if ('undefined' === typeof options) options = {};
options.json = true;
return this.toObject(options);
};
|
Helper for console.log
|
Document.prototype.toString =
Document.prototype.inspect = function (options) {
return inspect(this.toObject(options));
};
|
Returns true if the Document stores the same data as doc.
##
|
Document.prototype.equals = function (doc) {
return this.get('_id') === doc.get('_id');
};
|
Module exports.
|
module.exports = Document;
|
Document Validation Error
|
function ValidationError (instance) {
MongooseError.call(this, "Validation failed");
Error.captureStackTrace(this, arguments.callee);
this.name = 'ValidationError';
this.errors = instance.errors = {};
};
ValidationError.prototype.toString = function () {
return this.name + ': ' + Object.keys(this.errors).map(function (key) {
return String(this.errors[key]);
}, this).join(', ');
};
|
Inherits from MongooseError.
|
ValidationError.prototype.__proto__ = MongooseError.prototype;
Document.ValidationError = ValidationError;
|
Document Error
|
function DocumentError () {
MongooseError.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
this.name = 'DocumentError';
};
|
Inherits from MongooseError.
|
DocumentError.prototype.__proto__ = MongooseError.prototype;
exports.Error = DocumentError;
|
| lib/drivers/node-mongodb-native/binary.js |
Module dependencies.
|
var Binary = require('mongodb').BSONPure.Binary;
module.exports = exports = Binary;
|
| lib/drivers/node-mongodb-native/collection.js |
Module dependencies.
|
var Collection = require('../../collection')
, NativeCollection = require('mongodb').Collection
, utils = require('../../utils')
|
Inherit from abstract Collection.
|
MongooseCollection.prototype.__proto__ = Collection.prototype;
|
Copy the collection methods and make them subject to queues
|
for (var i in NativeCollection.prototype)
(function(i){
MongooseCollection.prototype[i] = function () {
if (!this.buffer) {
var collection = this.collection
, args = arguments
, self = this;
process.nextTick(function(){
var debug = self.conn.base.options.debug;
if (debug) {
if ('function' === typeof debug) {
debug.apply(debug
, [self.name, i].concat(utils.args(args, 0, args.length-1)));
} else {
console.error('\x1B[0;36mMongoose:\x1B[0m %s.%s(%s) %s %s %s'
, self.name
, i
, print(args[0])
, print(args[1])
, print(args[2])
, print(args[3]))
}
}
collection[i].apply(collection, args);
});
} else {
this.addQueue(i, arguments);
}
};
})(i);
|
Override signature of ensureIndex. -native one is not standard.
param: Object spec param: Object options param: Function callback api: public
|
var oldEnsureIndex = NativeCollection.prototype.ensureIndex;
function noop () {};
NativeCollection.prototype.ensureIndex = function(fields, options, fn){
if (!this.buffer) {
return oldEnsureIndex.apply(this, arguments);
}
};
|
Module exports.
|
module.exports = MongooseCollection;
|
| lib/drivers/node-mongodb-native/connection.js |
Module dependencies.
|
var Connection = require('../../connection')
, mongo = require('mongodb')
, Server = mongo.Server
, ReplSetServers = mongo.ReplSetServers;
|
Inherits from Connection.
|
NativeConnection.prototype.__proto__ = Connection.prototype;
|
Module exports.
|
module.exports = NativeConnection;
|
| lib/drivers/node-mongodb-native/objectid.js |
Module dependencies.
|
var ObjectId = require('mongodb').BSONPure.ObjectID;
|
| lib/error.js |
Inherits from Error.
|
MongooseError.prototype.__proto__ = Error.prototype;
|
Module exports.
|
module.exports = MongooseError;
|
| lib/index.js |
Module dependencies.
|
var Schema = require('./schema')
, SchemaType = require('./schematype')
, VirtualType = require('./virtualtype')
, SchemaTypes = Schema.Types
, SchemaDefaults = require('./schemadefault')
, Types = require('./types')
, Query = require('./query')
, Promise = require('./promise')
, Model = require('./model')
, Document = require('./document')
, utils = require('./utils');
|
Mongoose constructor. Most apps will only use one instance.
|
function Mongoose () {
this.connections = [];
this.plugins = [];
this.models = {};
this.modelSchemas = {};
this.options = {};
this.createConnection();
};
|
Sets/gets mongoose options
Examples
mongoose.set('test') // returns the 'test' value
mongoose.set('test', value) // sets the 'test' value
param: String key param: String value api: public
|
Mongoose.prototype.set =
Mongoose.prototype.get = function (key, value) {
if (arguments.length == 1)
return this.options[key];
this.options[key] = value;
return this;
};
|
Creates a Connection instance.
Examples
// with mongodb:// URI
db = mongoose.createConnection('mongodb://localhost:port/database');
// 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.prototype.createConnection = function () {
var conn = new Connection(this);
this.connections.push(conn);
if (arguments.length)
conn.open.apply(conn, arguments);
return conn;
};
|
Creates a replica set connection
|
function createSetConnection () {
var conn = new Connection(this);
this.connections.push(conn);
if (arguments.length)
conn.openSet.apply(conn, arguments);
return conn;
};
Mongoose.prototype.createSetConnection =
utils.dep('Mongoose#createSetConnection'
, 'Mongoose#createConnection in v3'
, createSetConnection);
|
Connects the default mongoose connection
|
Mongoose.prototype.connect = function (){
this.connection.open.apply(this.connection, arguments);
return this;
};
|
Connects the default mongoose connection to a replica set
|
function connectSet () {
this.connection.openSet.apply(this.connection, arguments);
return this;
};
Mongoose.prototype.connectSet =
utils.dep('Mongoose#connectSet', 'Mongoose#connect in v3', connectSet);
|
Disconnects from all connections.
|
Mongoose.prototype.disconnect = function (fn) {
var count = this.connections.length;
this.connections.forEach(function(conn){
conn.close(function(err){
if (err) return fn(err);
if (fn)
--count || fn();
});
});
return this;
};
|
Defines a model or retrieves it
param: String model name param: Schema schema object param: String collection name (optional, induced from model name) param: Boolean whether to skip initialization (defaults to false) api: public
|
Mongoose.prototype.model = function (name, schema, collection, skipInit) {
if (!(schema instanceof Schema)) {
collection = schema;
schema = false;
}
if ('boolean' === typeof collection) {
skipInit = collection;
collection = null;
}
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(t been registered for model "' + name + '".\n'
+ 'Use mongoose.model(name, schema)');
}
}
if (!schema) {
schema = this.modelSchemas[name];
}
if (!collection) {
collection = schema.set('collection') || utils.toCollectionName(name);
}
if (!this.models[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];
};
|
Declares a plugin executed on Schemas. Equivalent to calling .plugin(fn)
on each Schema you create.
|
Mongoose.prototype.plugin = function (fn, opts) {
this.plugins.push([fn, opts]);
return this;
};
|
Default connection
|
Mongoose.prototype.__defineGetter__('connection', function(){
return this.connections[0];
});
|
Driver depentend APIs
|
var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
|
Connection
|
var Connection = require(driver + '/connection');
|
Collection
|
var Collection = require(driver + '/collection');
|
Export default singleton.
|
module.exports = exports = new Mongoose();
|
Collection
|
exports.Collection = Collection;
|
Connection
|
exports.Connection = Connection;
|
Exports Mongoose version
|
exports.version = JSON.parse(
require('fs').readFileSync(__dirname + '/../package.json', 'utf8')
).version;
|
Export Mongoose constructor
|
exports.Mongoose = Mongoose;
|
Export Schema constructor
|
exports.Schema = Schema;
|
Export SchemaType constructor.
|
exports.SchemaType = SchemaType;
|
Export VirtualType constructor.
|
exports.VirtualType = VirtualType;
|
Export Schema types
|
exports.SchemaTypes = SchemaTypes;
|
Export types
|
exports.Types = Types;
|
Export Query
|
exports.Query = Query;
|
Export Promise
|
exports.Promise = Promise;
|
Export Model constructor
|
exports.Model = Model;
|
Export Document constructor
|
exports.Document = Document;
|
Export MongooseError
|
exports.Error = require('./error');
exports.mongo = require('mongodb');
|
| lib/model.js |
Module dependencies.
|
var Document = require('./document')
, MongooseArray = require('./types/array')
, MongooseBuffer = require('./types/buffer')
, MongooseError = require('./error')
, Query = require('./query')
, utils = require('./utils')
, isMongooseObject = utils.isMongooseObject
, EventEmitter = utils.EventEmitter
, merge = utils.merge
, Promise = require('./promise')
, tick = utils.tick
|
Model constructor
|
function Model (doc, fields) {
Document.call(this, doc, fields);
};
|
Inherits from Document.
|
Model.prototype.__proto__ = Document.prototype;
|
Connection the model uses. Set by the Connection or if absent set to the
default mongoose connection;
|
Model.prototype.db;
|
Collection the model uses. Set by Mongoose instance
|
Model.prototype.collection;
|
Model name.
|
Model.prototype.modelName;
|
Saves this document.
|
Model.prototype.save = function save (fn) {
var promise = new Promise(fn)
, complete = handleSave(promise, this)
, options = {}
if (this.options.safe) {
options.safe = this.options.safe;
}
if (this.isNew) {
this.collection.insert(this.toObject({ depopulate: 1 }), options, complete);
this._reset();
this.isNew = false;
this.emit('isNew', false);
this._inserting = true;
} else {
this._inserting = false;
var delta = this._delta();
this._reset();
if (delta) {
var where = this._where();
this.collection.update(where, delta, options, complete);
} else {
complete(null);
}
this.emit('isNew', false);
}
};
|
Remove the document
param: Function callback api: public
|
Model.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.options.safe) {
options.safe = this.options.safe;
}
this.collection.remove(where, options, tick(function (err) {
if (err) {
promise.error(err);
promise = self = self._removing = where = options = null;
return;
}
promise.complete();
self.emit('remove', self);
promise = self = where = options = null;
}));
return this;
};
|
Shortcut to access another model.
param: String model name api: public
|
Model.prototype.model = function model (name) {
return this.db.model(name);
};
|
Give the constructor the ability to emit events.
|
for (var i in EventEmitter.prototype)
Model[i] = EventEmitter.prototype[i];
|
Document schema
|
Model.schema;
|
Database instance the model uses.
|
Model.db;
|
Collection the model uses.
|
Model.collection;
|
Define properties that access the prototype.
|
['db', 'collection', 'schema', 'options', 'model'].forEach(function(prop){
Model.__defineGetter__(prop, function(){
return this.prototype[prop];
});
});
|
Module exports.
|
module.exports = exports = Model;
Model.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);
};
|
Finds documents
Examples
// retrieve only certain keys
MyModel.find({ name: /john/i }, ['name', 'friends'], function () { })
// pass options
MyModel.find({ name: /john/i }, [], { skip: 10 } )
|
Model.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);
};
|
Finds by id
|
Model.findById = function findById (id, fields, options, callback) {
return this.findOne({ _id: id }, fields, options, callback);
};
|
Finds one document
|
Model.findOne = function findOne (conditions, fields, options, callback) {
if ('function' == typeof options) {
callback = options;
options = null;
} else if ('function' == typeof fields) {
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);
};
|
Counts documents
|
Model.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);
};
Model.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);
};
|
where enables a very nice sugary api for doing your queries.
For example, instead of writing:
User.find({age: {$gte: 21, $lte: 65}}, callback);
we can instead write more readably:
User.where('age').gte(21).lte(65);
Moreover, you can also chain a bunch of these together like:
User
.where('age').gte(21).lte(65)
.where('name', /^b/i) // All names that begin where b or B
.where('friends').slice(10);
##
|
Model.where = function where (path, val) {
var q = new Query().bind(this, 'find');
return q.where.apply(q, arguments);
};
|
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.
|
Model.$where = function $where () {
var q = new Query().bind(this, 'find');
return q.$where.apply(q, arguments);
};
|
Shortcut for creating a new Document that is automatically saved
to the db if valid.
param: Object doc param: Function callback api: public
|
Model.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);
});
});
};
|
Updates documents.
Examples
MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn);
MyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, fn);
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)
param: Object conditions param: Object doc param: Object options param: Function callback return: Query api: public
|
Model.update = function update (conditions, doc, options, callback) {
if (arguments.length < 4) {
if ('function' === typeof options) {
callback = options;
options = null;
} else if ('function' === typeof doc) {
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);
};
|
| lib/namedscope.js |
var Query = require('./query');
function NamedScope () {}
NamedScope.prototype.query;
NamedScope.prototype.where = function () {
var q = this.query || (this.query = new Query());
q.where.apply(q, arguments);
return q;
};
|
*
* Decorate
*
* @param {NamedScope} target
* @param {Object} getters
* @api private
|
NamedScope.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;
|
|
| lib/promise.js |
Module dependencies.
|
var util = require('./utils');
var EventEmitter = util.EventEmitter;
|
Promise constructor.
|
function Promise (back) {
this.emitted = {};
if ('function' == typeof back)
this.addBack(back);
};
|
Inherits from EventEmitter.
|
Promise.prototype.__proto__ = EventEmitter.prototype;
|
Adds an event or fires the callback right away.
return: promise api: public
|
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;
};
|
Shortcut for emitting complete event
|
Promise.prototype.complete = function () {
var args = util.args(arguments);
return this.emit.apply(this, ['complete'].concat(args));
};
|
Shortcut for emitting err event
|
Promise.prototype.error = function (err) {
if (!(err instanceof Error)) err = new Error(err);
return this.emit('err', err);
};
|
Shortcut for .on('complete', fn)
return: promise api: public
|
Promise.prototype.addCallback = function (fn) {
return this.on('complete', fn);
};
|
Shortcut for .on('err', fn)
return: promise api: public
|
Promise.prototype.addErrback = function (fn) {
return this.on('err', fn);
};
|
Sugar for handling cases where you may be
resolving to either an error condition or a
success condition.
|
Promise.prototype.resolve = function (err, val) {
if (err) return this.error(err);
return this.complete(val);
};
|
Module exports.
|
module.exports = Promise;
|
| lib/querystream.js |
Module dependencies.
|
var Stream = require('stream').Stream
var utils = require('./utils')
|
QueryStream
Returns a stream interface for the query .
param: Query query return: Stream
|
function 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;
var self = this;
process.nextTick(function () {
self._init();
});
}
|
Flag stating whether or not this stream is readable.
|
QueryStream.prototype.readable;
|
Flag stating whether or not this stream is paused.
|
QueryStream.prototype.paused;
var T_INIT = 0;
var T_IDLE = 1;
var T_CONT = 2;
|
Pauses this stream.
|
QueryStream.prototype.pause = function () {
this.paused = true;
}
|
Resumes this stream.
|
QueryStream.prototype.resume = function () {
this.paused = false;
this._next();
}
|
Destroys the stream, closing the underlying
cursor. No more events will be emitted.
|
QueryStream.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');
}
module.exports = exports = QueryStream;
|
| lib/query.js |
Module dependencies.
|
var utils = require('./utils')
, merge = utils.merge
, Promise = require('./promise')
, Document = require('./document')
, inGroupsOf = utils.inGroupsOf
, tick = utils.tick
, QueryStream = require('./querystream')
|
Binds this query to a model.
##
param: Function param return: Query api: public
|
Query.prototype.bind = function bind (model, op, updateArg) {
this.model = model;
this.op = op;
if (op === 'update') this._updateArg = updateArg;
return this;
};
|
Executes the query returning a promise.
Examples
query.exec();
query.exec(callback);
query.exec('update');
query.exec('find', callback);
|
Query.prototype.exec = function (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.update(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;
};
|
Finds documents.
param: Object criteria param: Function callback api: public
|
Query.prototype.find = function (criteria, callback) {
this.op = 'find';
if ('function' === typeof criteria) {
callback = criteria;
criteria = {};
} else if (criteria instanceof Query) {
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);
};
|
Casts obj, or if obj is not present, then this._conditions,
based on the model's schema.
|
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) {
continue;
}
schematype = schema.path(path);
if (!schematype) {
var split = path.split('.')
, j = split.length
, pathFirstHalf
, pathLastHalf
, remainingConds
, castingQuery;
while (j--) {
pathFirstHalf = split.slice(0, j).join('.');
schematype = schema.path(pathFirstHalf);
if (schematype) break;
}
if (schematype) {
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);
}
}
}
};
|
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.
|
Query.prototype.$where = function (js) {
this._conditions['$where'] = js;
return this;
};
|
where enables a very nice sugary api for doing your queries.
For example, instead of writing:
User.find({age: {$gte: 21, $lte: 65}}, callback);
we can instead write more readably:
User.where('age').gte(21).lte(65);
Moreover, you can also chain a bunch of these together like:
User
.where('age').gte(21).lte(65)
.where('name', /^b/i) // All names that begin where b or B
.where('friends').slice(10);
|
Query.prototype.where = function (path, val) {
if (2 === arguments.length) {
this._conditions[path] = val;
}
this._currPath = path;
return this;
};
|
equals sugar.
User.where('age').equals(49);
Same as
User.where('age', 49);
param: object val return: Query api: public
|
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;
}
|
or
|
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;
}
|
nor
|
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;
}
|
gt, gte, lt, lte, ne, in, nin, all, regex, size, maxDistance
Can be used on Numbers or Dates.
Thing.where('type').nin(array)
|
'gt gte lt lte ne in nin all regex size maxDistance'.split(' ').forEach(function ($conditional) {
Query.prototype[$conditional] = function (path, val) {
if (arguments.length === 1) {
val = path;
path = this._currPath
}
var conds = this._conditions[path] || (this._conditions[path] = {});
conds['$' + $conditional] = val;
return this;
};
Query.prototype['$' + $conditional] = utils.dep('Query#$'+ $conditional, 'Query#' + $conditional, Query.prototype[$conditional]);
});
|
mod, near
|
;['mod', 'near'].forEach( function ($conditional) {
Query.prototype[$conditional] = 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['$' + $conditional] = val;
return this;
};
});
|
exists
|
Query.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;
};
|
elemMatch
|
Query.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
|
Object.defineProperty(Query.prototype, 'within', {
get: function () { return this }
});
Query.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;
};
Query.prototype.center = function (path, val) {
if (arguments.length === 1) {
val = path;
path = this._currPath;
}
var conds = this._conditions[path] || (this._conditions[path] = {});
conds['$within'] = { '$center': [val.center, val.radius] };
return this;
};
Query.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;
};
|
select
Chainable method for specifying which fields
to include or exclude from the document that is
returned from MongoDB.
Examples
query.fields({a: 1, b: 1, c: 1, _id: 0});
query.fields('a b c');
|
Query.prototype.select = function () {
var arg0 = arguments[0];
if (!arg0) return this;
if ('Object' === arg0.constructor.name || Array.isArray(arg0)) {
this._applyFields(arg0);
} else if (arguments.length === 1 && typeof arg0 === 'string') {
this._applyFields({only: arg0});
} else {
this._applyFields({only: this._parseOnlyExcludeFields.apply(this, arguments)});
}
return this;
};
|
slice()
|
Query.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;
};
|
sort
Sets the sort
Examples
query.sort('test', 1)
query.sort('field', -1)
query.sort('field', -1, 'test', 1)
|
Query.prototype.sort = function () {
var sort = this.options.sort || (this.options.sort = []);
inGroupsOf(2, arguments, function (field, value) {
sort.push([field, value]);
});
return this;
};
;['limit', 'skip', 'maxscan', 'snapshot', 'batchSize', 'comment'].forEach( function (method) {
Query.prototype[method] = function (v) {
this.options[method] = v;
return this;
};
});
|
hint
Sets query hints.
Examples
new Query().hint({ indexA: 1, indexB: -1})
new Query().hint("indexA", 1, "indexB", -1)
param: Object | String v param: Int [multi] return: Query api: public
|
Query.prototype.hint = function (v, multi) {
var hint = this.options.hint || (this.options.hint = {})
, k
if (multi) {
inGroupsOf(2, arguments, function (field, val) {
hint[field] = val;
});
} else if ('Object' === v.constructor.name) {
for (k in v) {
hint[k] = v[k];
}
}
return this;
};
|
slaveOk
Sets slaveOk option.
new Query().slaveOk() <== true
new Query().slaveOk(true)
new Query().slaveOk(false)
|
Query.prototype.slaveOk = function (v) {
this.options.slaveOk = arguments.length ? !!v : true;
return this;
};
|
tailable
Sets tailable option.
new Query().tailable() <== true
new Query().tailable(true)
new Query().tailable(false)
|
Query.prototype.tailable = function (v) {
this.options.tailable = arguments.length ? !!v : true;
return this;
};
|
findOne
Casts the query, sends the findOne command to mongodb.
Upon receiving the document, we initialize a mongoose
document based on the returned document from mongodb,
and then we invoke a callback on our mongoose document.
|
Query.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;
}
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);
var casted = new model(undefined, fields);
delete casted._doc._id;
casted.init(doc, self, function (err) {
if (err) return promise.error(err);
promise.complete(casted);
});
}));
return this;
};
|
count
Casts this._conditions and sends a count
command to mongodb. Invokes a callback upon
receiving results
|
Query.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;
};
|
distinct
Casts this._conditions and sends a distinct
command to mongodb. Invokes a callback upon
receiving results
|
Query.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;
};
|
update
Casts the doc according to the model Schema and
sends an update command to MongoDB.
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' }}, ...)
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.prototype.update = function update (doc, callback) {
this.op = 'update';
this._updateArg = doc;
var model = this.model
, options = this._optionsForExec(model)
, fn = 'function' == typeof callback
, castQuery
, castDoc
try {
this.cast(model);
castQuery = this._conditions;
} catch (err) {
if (fn) return callback(err);
throw err;
}
try {
castDoc = this._castUpdate(doc);
} catch (err) {
if (fn) return callback(err);
throw err;
}
if (!fn) {
delete options.safe;
}
if (castDoc) {
model.collection.update(castQuery, castDoc, options, tick(callback));
} else {
process.nextTick(function () {
callback(null, 0);
});
}
return this;
};
|
remove
Casts the query, sends the remove command to
mongodb where the query contents, and then
invokes a callback upon receiving the command
result.
param: Function callback api: public
|
Query.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;
};
|
populate
Sets population options.
- api: public
|
Query.prototype.populate = function (path, fields, conditions, options) {
this.options.populate[path] =
new PopulateOptions(fields, conditions, options);
return this;
};
|
stream
Returns a stream interface
Example
Thing.find({ name: /^hello/ }).stream().pipe(res)
|
Query.prototype.stream = function stream () {
return new QueryStream(this);
}
|
Deprecated methods.
|
Query.prototype.$or = utils.dep('Query#$or', 'Query#or', Query.prototype.or);
Query.prototype.$nor =utils.dep('Query#$nor', 'Query#nor', Query.prototype.nor);
Query.prototype.run = utils.dep('Query#run', 'Query#exec', Query.prototype.exec);
Query.prototype.$mod = utils.dep('Query#$mod', 'Query#mod', Query.prototype.mod);
Query.prototype.$box = utils.dep('Query#$box', 'Query#box', Query.prototype.box);
Query.prototype.$near = utils.dep('Query#$near', 'Query#near', Query.prototype.near);
Query.prototype.$slice = utils.dep('Query#$slice', 'Query#slice', Query.prototype.slice);
Query.prototype.notEqualTo = utils.dep('Query#notEqualTo', 'Query#ne', Query.prototype.ne);
Query.prototype.fields = utils.dep('Query#fields', 'Query#select', Query.prototype.select);
Query.prototype.$exists =utils.dep('Query#$exists', 'Query#exists', Query.prototype.exists);
Query.prototype.$center = utils.dep('Query#$center', 'Query#center', Query.prototype.center);
Query.prototype.$elemMatch =utils.dep('Query#$elemMatch', 'Query#elemMatch', Query.prototype.elemMatch);
Query.prototype.$centerSphere = utils.dep('Query#$centerSphere', 'Query#centerSphere', Query.prototype.centerSphere);
|
asc
Sorts ascending.
query.asc('name', 'age');
|
function asc () {
var sort = this.options.sort || (this.options.sort = []);
for (var i = 0, l = arguments.length; i < l; i++) {
sort.push([arguments[i], 1]);
}
return this;
};
Query.prototype.asc = utils.dep('Query#asc', 'Query#sort', asc);
|
desc
Sorts descending.
query.desc('name', 'age');
|
function desc () {
var sort = this.options.sort || (this.options.sort = []);
for (var i = 0, l = arguments.length; i < l; i++) {
sort.push([arguments[i], -1]);
}
return this;
};
Query.prototype.desc = utils.dep('Query#desc', 'Query#sort', desc);
|
limit, skip, maxscan, snapshot, batchSize, comment
Sets these associated options.
query.comment('feed query');
|
'$within wherein $wherein'.split(' ').forEach(function (getter) {
var withinDep = utils.dep('Query#' + getter, 'Query#within')
Object.defineProperty(Query.prototype, getter, {
get: function () {
withinDep();
return this;
}
});
});
|
only
Chainable method for adding the specified fields to the
object of fields to only include.
Examples
query.only('a b c');
query.only('a', 'b', 'c');
query.only(['a', 'b', 'c']);
|
function only (fields) {
fields = this._parseOnlyExcludeFields.apply(this, arguments);
this._applyFields({ only: fields });
return this;
};
Query.prototype.only = utils.dep('Query#only', 'Query#select', only);
|
exclude
Chainable method for adding the specified fields to the
object of fields to exclude.
Examples
query.exclude('a b c');
query.exclude('a', 'b', 'c');
query.exclude(['a', 'b', 'c']);
|
function exclude (fields) {
fields = this._parseOnlyExcludeFields.apply(this, arguments);
this._applyFields({ exclude: fields });
return this;
};
Query.prototype.exclude = utils.dep('Query#exclude', 'Query#select', exclude);
|
each()
Streaming cursors.
The callback is called repeatedly for each document
found in the collection as it's streamed. If an error
occurs streaming stops.
Example
query.each(function (err, user) {
if (err) return res.end("aww, received an error. all done.");
if (user) {
res.write(user.name + '\n')
} else {
res.end("reached end of cursor. all done.");
}
});
A third parameter may also be used in the callback which
allows you to iterate the cursor manually.
Example
query.each(function (err, user, next) {
if (err) return res.end("aww, received an error. all done.");
if (user) {
res.write(user.name + '\n')
doSomethingAsync(next);
} else {
res.end("reached end of cursor. all done.");
}
});
param: Function callback return: Query deprecate: d api: public
|
function each (callback) {
var model = this.model
, options = this._optionsForExec(model)
, manual = 3 == callback.length
, self = this
try {
this.cast(model);
} catch (err) {
return callback(err);
}
var fields = utils.clone(options.fields = this._fields);
function complete (err, val) {
if (complete.ran) return;
complete.ran = true;
callback(err, val);
}
model.collection.find(this._conditions, options, function (err, cursor) {
if (err) return complete(err);
var ticks = 0;
next();
function next () {
if (!(++ticks % 20)) {
process.nextTick(function () {
cursor.nextObject(onNextObject);
});
} else {
cursor.nextObject(onNextObject);
}
}
function onNextObject (err, doc) {
if (err) return complete(err);
if (!doc) return complete(null, null);
var instance = new model(undefined, fields);
delete instance._doc._id;
instance.init(doc, self, function (err) {
if (err) return complete(err);
if (manual) {
callback(null, instance, next);
} else {
callback(null, instance);
next();
}
});
}
});
return this;
}
Query.prototype.each = utils.dep('Query#each', 'Query#stream', each);
|
Exports.
|
module.exports = Query;
module.exports.QueryStream = QueryStream;
|
| lib/schema/array.js |
Module dependencies.
|
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, NumberSchema = require('./number')
, Types = {
Boolean: require('./boolean')
, Date: require('./date')
, Number: ArrayNumberSchema
, String: require('./string')
, ObjectId: require('./objectid')
, Buffer: require('./buffer')
}
, MongooseArray = require('../types').Array
, Mixed = require('./mixed')
, Query = require('../query')
, isMongooseObject = require('../utils').isMongooseObject
|
Inherits from SchemaType.
|
SchemaArray.prototype.__proto__ = SchemaType.prototype;
|
Module exports.
|
module.exports = SchemaArray;
|
| lib/schema/boolean.js |
Module dependencies.
|
var SchemaType = require('../schematype');
|
Inherits from SchemaType.
|
SchemaBoolean.prototype.__proto__ = SchemaType.prototype;
|
Module exports.
|
module.exports = SchemaBoolean;
|
| lib/schema/buffer.js |
Module dependencies.
|
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, BufferNumberSchema = function () {}
, MongooseBuffer = require('../types').Buffer
, Binary = MongooseBuffer.Binary
, Query = require('../query');
|
Inherits from SchemaType.
|
SchemaBuffer.prototype.__proto__ = SchemaType.prototype;
|
Module exports.
|
module.exports = SchemaBuffer;
|
| lib/schema/date.js |
Module requirements.
|
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError;
|
Inherits from SchemaType.
|
SchemaDate.prototype.__proto__ = SchemaType.prototype;
|
Module exports.
|
module.exports = SchemaDate;
|
| lib/schema/documentarray.js |
Module dependencies.
|
var SchemaType = require('../schematype')
, ArrayType = require('./array')
, MongooseDocumentArray = require('../types/documentarray')
, Subdocument = require('../types/embedded')
, CastError = SchemaType.CastError
, Document = require('../document');
|
Inherits from ArrayType.
|
DocumentArray.prototype.__proto__ = ArrayType.prototype;
|
Module exports.
|
module.exports = DocumentArray;
|
| lib/schema/index.js |
Module exports.
|
exports.String = require('./string');
exports.Number = require('./number');
exports.Boolean = require('./boolean');
exports.DocumentArray = require('./documentarray');
exports.Array = require('./array');
exports.Buffer = require('./buffer');
exports.Date = require('./date');
exports.ObjectId = require('./objectid');
exports.Mixed = require('./mixed');
|
| lib/schema/mixed.js |
Module dependencies.
|
var SchemaType = require('../schematype');
|
Inherits from SchemaType.
|
Mixed.prototype.__proto__ = SchemaType.prototype;
|
Module exports.
|
module.exports = Mixed;
|
| lib/schema/number.js |
Module requirements.
|
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, MongooseNumber = require('../types/number');
|
Inherits from SchemaType.
|
SchemaNumber.prototype.__proto__ = SchemaType.prototype;
|
Sets a maximum number validator
|
SchemaNumber.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;
};
|
Sets a maximum number validator
|
SchemaNumber.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;
};
|
Module exports.
|
module.exports = SchemaNumber;
|
| lib/schema/objectid.js |
Module dependencies.
|
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, driver = global.MONGOOSE_DRIVER_PATH || './../drivers/node-mongodb-native'
, oid = require('../types/objectid');
|
Inherits from SchemaType.
|
ObjectId.prototype.__proto__ = SchemaType.prototype;
|
Module exports.
|
module.exports = ObjectId;
|
| lib/schema/string.js |
Module dependencies.
|
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError;
|
Inherits from SchemaType.
|
SchemaString.prototype.__proto__ = SchemaType.prototype;
|
Adds enumeration values
|
SchemaString.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 ~values.indexOf(v);
};
this.validators.push([this.enumValidator, 'enum']);
}
};
|
Adds a lowercase setter
|
SchemaString.prototype.lowercase = function () {
return this.set(function (v) {
return v.toLowerCase();
});
};
|
Adds an uppercase setter
|
SchemaString.prototype.uppercase = function () {
return this.set(function (v) {
return v.toUpperCase();
});
};
|
Adds a trim setter
|
SchemaString.prototype.trim = function () {
return this.set(function (v) {
return v.trim();
});
};
|
Sets a regexp test
|
SchemaString.prototype.match = function(regExp){
this.validators.push([function(v){
return regExp.test(v);
}, 'regexp']);
};
|
Module exports.
|
module.exports = SchemaString;
|
| lib/schema.js |
Module dependencies.
|
var EventEmitter = require('events').EventEmitter
, VirtualType = require('./virtualtype')
, utils = require('./utils')
, NamedScope
, Query
, Types
|
Schema constructor.
param: Object definition api: public
|
function Schema (obj, options) {
this.paths = {};
this.virtuals = {};
this.nested = {};
this.inherits = {};
this.callQueue = [];
this._indexes = [];
this.methods = {};
this.statics = {};
this.tree = {};
this.options = utils.options({
safe: true
, strict: false
}, options);
if (obj)
this.add(obj);
if (!this.paths['_id'] && !this.options.noId) {
this.add({ _id: {type: ObjectId, auto: true} });
}
if (!this.paths['id'] && !this.options.noVirtualId) {
this.virtual('id').get(function () {
if (this.__id) {
return this.__id;
}
return this.__id = null == this._id
? null
: this._id.toString();
});
}
delete this.options.noVirtualId;
};
|
Inherit from EventEmitter.
|
Schema.prototype.__proto__ = EventEmitter.prototype;
|
Sets the keys
param: Object keys param: String prefix api: public
|
Schema.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) {
this.nested[prefix + i] = true;
this.add(obj[i], prefix + i + '.');
}
else
this.path(prefix + i, obj[i]);
} else
this.path(prefix + i, obj[i]);
}
};
|
Sets a path (if arity 2)
Gets a path (if arity 1)
|
Schema.prototype.path = function (path, obj) {
if (obj == undefined) {
if (this.paths[path]) return this.paths[path];
var last
, self = this
, subpaths = path.split(/\.(\d+)\.?/)
.filter(Boolean)
if (subpaths.length > 1) {
last = subpaths.length - 1;
return subpaths.reduce(function (val, subpath, i) {
if (val && !val.schema) {
if (i === last && !/\D/.test(subpath) && val instanceof Types.Array) {
return val.caster;
} else {
return val;
}
}
if (!/\D/.test(subpath)) {
return val;
}
return val ? val.schema.path(subpath)
: self.path(subpath);
}, null);
}
return this.paths[subpaths[0]];
}
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;
};
|
Converts -- e.g., Number, [SomeSchema],
{ type: String, enum: ['m', 'f'] } -- into
the appropriate Mongoose Type, which we use
later for casting, validation, etc.
##
|
Schema.interpretAsType = function (path, obj) {
if (obj.constructor.name != 'Object')
obj = { type: obj };
var type = obj.type && !obj.type.type
? obj.type
: {};
if (type.constructor.name == 'Object') {
return new Types.Mixed(path, obj);
}
if (Array.isArray(type) || type == Array) {
var cast = type == Array
? obj.cast
: type[0];
if (cast instanceof Schema) {
return new Types.DocumentArray(path, cast, obj);
}
return new Types.Array(path, cast || Types.Mixed, obj);
}
if (undefined == Types[type.name]) {
throw new TypeError('Undefined type at `' + path +
'`\n Did you try nesting Schemas? ' +
'You can only nest using refs or arrays.');
}
return new Types[type.name](path, obj);
};
|
Iterates through the schema's paths, passing the path string and type object
to the callback.
|
Schema.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;
};
|
Returns an Array of path strings that are required.
- api: public
|
Object.defineProperty(Schema.prototype, 'requiredPaths', {
get: function () {
var paths = this.paths
, pathnames = Object.keys(paths)
, i = pathnames.length
, pathname, path
, requiredPaths = [];
while (i--) {
pathname = pathnames[i];
path = paths[pathname];
if (path.isRequired) requiredPaths.push(pathname);
}
return requiredPaths;
}
});
|
Given a path, returns whether it is a real, virtual,
nested, or ad-hoc/undefined path.
param: String path return: String api: public
|
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';
return 'adhocOrUndefined';
};
|
Defines a pre for the document
param: String method param: Function callback api: public
|
Schema.prototype.pre = function(){
return this.queue('pre', arguments);
};
|
Defines a post hook for the document.
param: String method param: Function callback api: public
|
Schema.prototype.post = function(method, fn){
return this.queue('on', arguments);
};
|
Registers a plugin for this schema
|
Schema.prototype.plugin = function (fn, opts) {
fn(this, opts);
return this;
};
|
Adds a method
|
Schema.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;
};
|
Defines a static method
param: String name param: Function handler api: public
|
Schema.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;
};
|
Defines an index (most likely compound)
## Example
schema.index({ first: 1, last: -1 })
|
Schema.prototype.index = function (fields, options) {
this._indexes.push([fields, options || {}]);
return this;
};
|
Sets/gets an option
|
Schema.prototype.set = function (key, value) {
if (arguments.length == 1)
return this.options[key];
this.options[key] = value;
return this;
};
|
Compiles indexes from fields and schema-level indexes
|
Schema.prototype.__defineGetter__('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;
indexes.push([field, 'Object' === index.constructor.name ? index : {} ]);
}
}
}
}
if (prefix) {
fixSubIndexPaths(schema, prefix);
} else {
indexes = indexes.concat(schema._indexes);
}
}
|
Checks for indexes added to subdocs using Schema.index().
These indexes need their paths prefixed properly.
schema._indexes = [ [indexObj, options], [indexObj, options] ..]
|
function fixSubIndexPaths (schema, prefix) {
var subindexes = schema._indexes
, len = subindexes.length
, indexObj
, newindex
, klen
, keys
, key
, i = 0
, j
for (i = 0; i < len; ++i) {
indexObj = subindexes[i][0];
keys = Object.keys(indexObj);
klen = keys.length;
newindex = {};
for (j = 0; j < klen; ++j) {
key = keys[j];
newindex[prefix + key] = indexObj[key];
}
indexes.push([newindex, subindexes[i][1]]);
}
}
});
|
Retrieves or creates the virtual type with the given name.
param: String name return: VirtualType
|
Schema.prototype.virtual = function (name, options) {
var virtuals = this.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);
};
|
Fetches the virtual type with the given name.
Should be distinct from virtual because virtual auto-defines a new VirtualType
if the path doesn't exist.
param: String name return: VirtualType
|
Schema.prototype.virtualpath = function (name) {
return this.virtuals[name];
};
Schema.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;
};
|
ObjectId schema identifier. Not an actual ObjectId, only used for Schemas.
|
function ObjectId () {
throw new Error('This is an abstract interface. Its only purpose is to mark '
+ 'fields as ObjectId in the schema creation.');
}
|
Module exports.
|
module.exports = exports = Schema;
exports.Types = Types = require('./schema/index');
NamedScope = require('./namedscope')
Query = require('./query');
exports.ObjectId = ObjectId;
|
| lib/schemadefault.js |
Module dependencies.
|
var Schema = require('./schema')
|
Default model for querying the system.profiles
collection (it only exists when profiling is
enabled.
|
exports['system.profile'] = new Schema({
ts: Date
, info: String
, millis: Number
, op: String
, ns: String
, query: Schema.Types.Mixed
, updateobj: Schema.Types.Mixed
, ntoreturn: Number
, nreturned: Number
, nscanned: Number
, responseLength: Number
, client: String
, user: String
, idhack: Boolean
, scanAndOrder: Boolean
, keyUpdates: Number
, cursorid: Number
}, { noVirtualId: true, noId: true });
|
| lib/schematype.js |
Module dependencies.
|
var MongooseError = require('./error');
var utils = require('./utils');
|
SchemaType constructor
param: String path api: public
|
function 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]) {
var opts = Array.isArray(options[i])
? options[i]
: [options[i]];
this[i].apply(this, opts);
}
};
|
Sets a default
|
SchemaType.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;
};
|
Sets index. It can be a boolean or a hash of options
## Example
Schema.path('my.path').index(true);
Schema.path('my.path').index({ unique: true });
"Direction doesn't matter for single key indexes"
http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeysIndexes
param: Object true/ api: public
|
SchemaType.prototype.index = function (index) {
this._index = index;
return this;
};
|
Adds a setter
param: Function setter api: public
|
SchemaType.prototype.set = function (fn) {
if ('function' != typeof fn)
throw new Error('A setter must be a function.');
this.setters.push(fn);
return this;
};
|
Adds a getter
param: Function getter api: public
|
SchemaType.prototype.get = function (fn) {
if ('function' != typeof fn)
throw new Error('A getter must be a function.');
this.getters.push(fn);
return this;
};
|
validate
Adds validators.
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 }});
|
SchemaType.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];
this.validators.push([arg.validator, arg.msg]);
}
return this;
};
|
Adds a required validator
|
SchemaType.prototype.required = function (required) {
var self = this;
function __checkRequired (v) {
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;
};
|
select
Set default select() behavior for this path. 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.
T = db.model('T', new Schema({ x: { type: String, select: true }}));
T.find(..); // x will always be selected ..
// .. unless overridden;
T.find().select({ x: 0 }).exec();
|
SchemaType.prototype.select = function select (val) {
this.selected = !! val;
}
|
Inherits from MongooseError
|
ValidatorError.prototype.__proto__ = MongooseError.prototype;
|
Inherits from MongooseError.
|
CastError.prototype.__proto__ = MongooseError.prototype;
|
Module exports.
|
module.exports = exports = SchemaType;
exports.CastError = CastError;
exports.ValidatorError = ValidatorError;
|
| lib/statemachine.js |
Module dependencies.
|
var utils = require('./utils');
|
| lib/types/array.js |
Module dependencies.
|
var EmbeddedDocument = require('./embedded');
var Document = require('../document');
var ObjectId = require('./objectid');
var utils = require('../utils')
|
Inherit from Array
|
MongooseArray.prototype = new Array;
|
Marks this array as modified.
It is called during a nonAtomicPush, an atomic opteration,
or by an existing embedded document that is modified.
If it bubbles up from an embedded document change,
then it takes the following arguments (otherwise, takes
0 arguments)
##
|
MongooseArray.prototype._markModified = function (embeddedDoc, embeddedPath) {
var parent = this._parent
, dirtyPath;
if (parent) {
if (arguments.length) {
dirtyPath = [this._path, this.indexOf(embeddedDoc), embeddedPath].join('.');
} else {
dirtyPath = this._path;
}
parent.markModified(dirtyPath);
}
return this;
};
|
Returns true if we have to perform atomics for this, and no normal
operations
|
MongooseArray.prototype.__defineGetter__('doAtomics', function () {
if (!(this._atomics && 'Object' === this._atomics.constructor.name)) {
return 0;
}
return Object.keys(this._atomics).length;
});
|
Pushes item/s to the array atomically. Overrides Array#push
param: Object value api: public
|
MongooseArray.prototype.push = function () {
var values = [].map.call(arguments, this._cast, this)
, ret = [].push.apply(this, values);
this._registerAtomic('$pushAll', values);
return ret;
};
MongooseArray.prototype.$push =
utils.dep('MongooseArray#$push'
, 'MongooseArray#push', MongooseArray.prototype.push);
|
Pushes item/s to the array non-atomically
param: Object value api: public
|
MongooseArray.prototype.nonAtomicPush = function () {
var values = [].map.call(arguments, this._cast, this)
, ret = [].push.apply(this, values);
this._markModified();
return ret;
};
|
Pushes several items at once to the array atomically
param: Array values api: public deprecate: d
|
function $pushAll (value) {
var length = this.length;
this.nonAtomicPush.apply(this, value);
this._registerAtomic('$pushAll', this.slice(length));
return this;
};
MongooseArray.prototype.$pushAll =
utils.dep('MongooseArray#$pushAll'
, 'MongooseArray#push in v3', $pushAll);
|
Pops the array atomically
|
MongooseArray.prototype.pop =
MongooseArray.prototype.$pop = function () {
this._registerAtomic('$pop', 1);
return [].pop.call(this)
};
|
Atomically shifts the array.
Only works once per doc.save(). Calling this mulitple
times on an array before saving is the same as calling
it once.
|
MongooseArray.prototype.shift =
MongooseArray.prototype.$shift = function $shift () {
this._registerAtomic('$pop', -1);
return [].shift.call(this)
};
|
Removes items from an array atomically
Examples
doc.array.remove(ObjectId)
doc.array.remove('tag 1', 'tag 2')
|
MongooseArray.prototype.remove = function () {
var args = [].map.call(arguments, this._cast, this);
if (args.length == 1)
this.$pull(args[0]);
else
this.$pullAll(args);
return args;
};
|
Pulls from the array
|
MongooseArray.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;
};
MongooseArray.prototype.$pull =
utils.dep('MongooseArray#$pull'
, 'MongooseArray#pull', MongooseArray.prototype.pull);
|
Pulls many items from an array
|
function $pullAll (values) {
if (values && values.length) {
var oldArr = this._parent.get(this._path)
, i = oldArr.length, mem;
while (i--) {
mem = oldArr[i];
if (mem instanceof EmbeddedDocument) {
if (values.some( function (v) { return v.equals(mem); } )) {
oldArr.splice(i, 1);
}
} else if (~values.indexOf(mem)) oldArr.splice(i, 1);
}
if (values[0] instanceof EmbeddedDocument) {
this._registerAtomic('$pullDocs', values.map( function (v) { return v._id; } ));
} else {
this._registerAtomic('$pullAll', values);
}
}
return this;
};
MongooseArray.prototype.$pullAll =
utils.dep('MongooseArray#$pullAll', 'MongooseArray#pull', $pullAll);
|
Splices the array.
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.prototype.splice = function () {
var result = [].splice.apply(this, arguments);
this._markModified();
return result;
};
|
Non-atomically unshifts onto the array.
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.prototype.unshift = function () {
var values = [].map.call(arguments, this._cast, this);
[].unshift.apply(this, values);
this._markModified();
return this.length;
};
MongooseArray.prototype.$unshift =
utils.dep('MongooseArray#$unshift'
, 'MongooseArray#unshift', MongooseArray.prototype.unshift);
|
Adds values to the array if not already present.
- api: public
|
MongooseArray.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;
};
MongooseArray.prototype.$addToSet =
utils.dep('MongooseArray#$addToSet'
, 'MongooseArray#addToSet', MongooseArray.prototype.addToSet);
|
Returns an Array
return: Array api: public
|
MongooseArray.prototype.toObject = function (options) {
if (options && options.depopulate && this[0] instanceof Document) {
return this.map(function (doc) {
return doc._id;
});
}
return this.map(function (doc) {
return doc;
});
};
|
Helper for console.log
|
MongooseArray.prototype.inspect = function () {
return '[' + this.map(function (doc) {
return ' ' + doc;
}) + ' ]';
};
|
Return the index of obj or -1.
param: Object obj return: Number api: public
|
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;
};
|
Module exports.
|
module.exports = exports = MongooseArray;
|
| lib/types/buffer.js |
Access driver.
|
var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native';
|
Module dependencies.
|
var Binary = require(driver + '/binary');
|
Inherit from Buffer.
|
MongooseBuffer.prototype = new Buffer(0);
|
Marks this buffer as modified.
|
MongooseBuffer.prototype._markModified = function () {
var parent = this._parent;
if (parent) {
parent.markModified(this._path);
}
return this;
};
|
Writes the buffer.
|
MongooseBuffer.prototype.write = function () {
var written = Buffer.prototype.write.apply(this, arguments);
if (written > 0) {
this._markModified();
}
return written;
};
|
Copy the buffer.
Note Buffer#copy will not mark target as modified so
you must copy from a MongooseBuffer for it to work
as expected.
Work around since copy modifies the target, not this.
|
MongooseBuffer.prototype.copy = function (target) {
var ret = Buffer.prototype.copy.apply(this, arguments);
if (target instanceof MongooseBuffer) {
target._markModified();
}
return ret;
};
|
Compile other Buffer methods marking this buffer as modified.
|
;(
'writeUInt8 writeUInt16 writeUInt32 writeInt8 writeInt16 writeInt32 ' +
'writeFloat writeDouble fill ' +
'utf8Write binaryWrite asciiWrite set ' +
'writeUInt16LE writeUInt16BE writeUInt32LE writeUInt32BE ' +
'writeInt16LE writeInt16BE writeInt32LE writeInt32BE ' +
'writeFloatLE writeFloatBE writeDoubleLE writeDoubleBE'
).split(' ').forEach(function (method) {
if (!Buffer.prototype[method]) return;
MongooseBuffer.prototype[method] = new Function(
'var ret = Buffer.prototype.'+method+'.apply(this, arguments);' +
'this._markModified();' +
'return ret;'
)
});
|
Returns a Binary.
return: Buffer api: public
|
MongooseBuffer.prototype.toObject = function () {
return new Binary(this, x00);
};
|
Module exports.
|
MongooseBuffer.Binary = Binary;
module.exports = MongooseBuffer;
|
| lib/types/document.js |
Module dependencies.
|
var Document = require('../document')
, inspect = require('util').inspect;
|
Inherit from Document
|
EmbeddedDocument.prototype.__proto__ = Document.prototype;
|
Override set to mark the parent as modified
|
var oldSet = Document.prototype.set;
EmbeddedDocument.prototype.set = function (path) {
this.markModified(path);
return oldSet.apply(this, arguments);
};
|
Save the subdocument
|
EmbeddedDocument.prototype.save = function(fn) {
if (fn)
fn(null);
this.emit('save', this);
return this;
};
|
Remove the subdocument
|
EmbeddedDocument.prototype.remove = function (fn) {
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;
};
|
Helper for console.log
|
EmbeddedDocument.prototype.inspect = function () {
return inspect(this.toObject());
};
|
Module exxports.
|
module.exports = EmbeddedDocument;
|
| lib/types/documentarray.js |
Module dependencies.
|
var MongooseArray = require('./array')
, driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native'
, ObjectId = require(driver + '/objectid')
, ObjectIdSchema = require('../schema/objectid');
|
Inherits from MongooseArray
|
MongooseDocumentArray.prototype.__proto__ = MongooseArray.prototype;
|
Filters items by id
param: Object id api: public
|
MongooseDocumentArray.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 an Array and converts any Document
members toObject.
return: Array api: public
|
MongooseDocumentArray.prototype.toObject = function () {
return this.map(function (doc) {
return doc && doc.toObject() || null;
});
};
|
Helper for console.log
|
MongooseDocumentArray.prototype.inspect = function () {
return '[' + this.map(function (doc) {
return doc && doc.inspect() || 'null';
}).join('\n') + ']';
};
|
Module exports.
|
module.exports = MongooseDocumentArray;
|
| lib/types/embedded.js |
Module dependencies.
|
var Document = require('../document')
, inspect = require('util').inspect;
|
Inherit from Document
|
EmbeddedDocument.prototype.__proto__ = Document.prototype;
|
Noop. Does not actually save the doc to the db.
|
EmbeddedDocument.prototype.save = function(fn) {
if (fn)
fn(null);
return this;
};
|
Remove the subdocument
|
EmbeddedDocument.prototype.remove = function (fn) {
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;
};
|
Helper for console.log
|
EmbeddedDocument.prototype.inspect = function () {
return inspect(this.toObject());
};
|
Module exports.
|
module.exports = EmbeddedDocument;
|
| lib/types/index.js |
Module exports.
|
exports.Array = require('./array');
exports.Buffer = require('./buffer');
exports.Document =
exports.Embedded = require('./embedded');
exports.DocumentArray = require('./documentarray');
exports.Number = require('./number');
exports.ObjectId = require('./objectid');
|
| lib/types/number.js |
Module dependencies.
|
var utils = require('./../utils')
|
Inherits from Number.
|
MongooseNumber.prototype = new Number();
var depInc = utils.dep('MongooseNumber#$inc / MongooseNumber#increment', 'Model.update() to get incrementation in v3');
var depDec = utils.dep('MongooseNumber#decrement', 'Model.update() to get decrementation in v3');
|
Atomic increment
|
function increment (value) {
depInc();
var schema = this._parent.schema.path(this._path)
, value = Number(value) || 1;
if (isNaN(value)) value = 1;
this._parent.setValue(this._path, schema.cast(this + value));
this._parent.getValue(this._path)._atomics['$inc'] = value || 1;
this._parent._activePaths.modify(this._path);
return this;
};
MongooseNumber.prototype.$inc =
MongooseNumber.prototype.increment = increment;
|
Returns true if we have to perform atomics for this, and no normal
operations
|
MongooseNumber.prototype.__defineGetter__('doAtomics', function () {
return Object.keys(this._atomics).length;
});
|
Atomic decrement
|
MongooseNumber.prototype.decrement = function(){
depDec();
this.increment(-1);
};
|
Re-declare toString (for console.log )
|
MongooseNumber.prototype.inspect =
MongooseNumber.prototype.toString = function () {
return String(this.valueOf());
};
|
Module exports
|
module.exports = MongooseNumber;
|
| lib/types/objectid.js |
Access driver.
|
var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native';
|
Module exports.
|
module.exports = require(driver + '/objectid');
|
| lib/utils.js |
Module dependencies.
|
var EventEmitter = require('events').EventEmitter
, ObjectId = require('./types/objectid')
, MongooseBuffer
, MongooseArray
, Document
|
Pluralization rules.
|
var rules = [
[/(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']
];
|
Uncountable words.
|
var 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'
];
|
Inherit from EventEmitter.
|
Events.prototype.__proto__ = EventEmitter.prototype;
|
Add once .
|
Events.prototype.once = function (type, listener) {
var self = this;
self.on(type, function g(){
self.removeListener(type, g);
listener.apply(this, arguments);
});
};
}
exports.EventEmitter = Events;
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;
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) {
return false;
}
if (ka.length != kb.length)
return false;
ka.sort();
kb.sort();
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!deepEqual(a[key], b[key])) return false;
}
return true;
};
|
Merges from into to without overwriting
existing properties of to .
param: Object to param: Object from
|
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]);
}
}
};
|
A faster Array.prototype.slice.call(arguments) alternative
|
exports.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;
}
|
Returns if v is a mongoose object that has
a toObject() method we can use. This is for
compatibility with libs like Date.js which do
foolish things to Natives.
|
var isMongooseObject = 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
}
|
API deprecation helper.
Disable deprecation warnings by setting the
MONGOOSEDEPWARNINGS environment variable to false, or
mongoose.set('dep warnings', false);
|
var warn =false;
;(exports.dep = function deprecate (old, rec, fn, scope) {
return function () {
if (warn && !exports.dep.cache[old]) {
exports.dep.cache[old] = 1;
console.warn('*** Mongoose %s is deprecated. Use %s instead.', old, rec);
}
return fn
? fn.apply(scope || this, arguments)
: undefined
}
}).cache = {};
process.nextTick(function () {
var mongoose = require('./index');
var val = mongoose.set('dep warnings');
if ('boolean' == typeof val) {
warn = val;
} else if ('false' !== process.env.MONGOOSE_DEP_WARNINGS) {
warn = true;
}
});
|
| lib/virtualtype.js |
VirtualType constructor
This is what mongoose uses to define virtual attributes via
Schema.prototype.virtual
|
function VirtualType (options) {
this.getters = [];
this.setters = [];
this.options = options || {};
}
|
Adds a getter
param: Function fn return: VirtualType this api: public
|
VirtualType.prototype.get = function (fn) {
this.getters.push(fn);
return this;
};
|
Adds a setter
param: Function fn return: VirtualType this api: public
|
VirtualType.prototype.set = function (fn) {
this.setters.push(fn);
return this;
};
|
Applies getters
param: Object value param: Object scope api: public
|
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;
};
|
Applies setters
param: Object value param: Object scope api: public
|
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;
};
module.exports = VirtualType;
|