function ES6Promise() {
throw new Error('Can\'t use ES6 promise with mpromise style constructor');
}n/a
function Aggregate() {
this._pipeline = [];
this._model = undefined;
this.options = undefined;
if (arguments.length === 1 && util.isArray(arguments[0])) {
this.append.apply(this, arguments[0]);
} else {
this.append.apply(this, arguments);
}
}...
* ####Example:
*
* new Aggregate();
* new Aggregate({ $project: { a: 1, b: 1 } });
* new Aggregate({ $project: { a: 1, b: 1 } }, { $skip: 5 });
* new Aggregate([{ $project: { a: 1, b: 1 } }, { $skip: 5 }]);
*
* Returned when calling Model.aggregate().
*
* ####Example:
*
* Model
* .aggregate({ $match: { age: { $gte: 21 }}})
* .unwind('tags')
* .exec(callback)
...function SchemaArray(key, cast, options, schemaOptions) {
var typeKey = 'type';
if (schemaOptions && schemaOptions.typeKey) {
typeKey = schemaOptions.typeKey;
}
if (cast) {
var castOptions = {};
if (utils.getFunctionName(cast.constructor) === 'Object') {
if (cast[typeKey]) {
// support { type: Woot }
castOptions = utils.clone(cast); // do not alter user arguments
delete castOptions[typeKey];
cast = cast[typeKey];
} else {
cast = Mixed;
}
}
// support { type: 'String' }
var name = typeof cast === 'string'
? cast
: utils.getFunctionName(cast);
var caster = name in Types
? Types[name]
: cast;
this.casterConstructor = caster;
if (typeof caster === 'function') {
this.caster = new caster(null, castOptions);
} else {
this.caster = caster;
}
if (!(this.caster instanceof EmbeddedDoc)) {
this.caster.path = key;
}
}
SchemaType.call(this, key, options, 'Array');
var defaultArr;
var fn;
if (this.defaultValue != null) {
defaultArr = this.defaultValue;
fn = typeof defaultArr === 'function';
}
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
this.default(function() {
var arr = [];
if (fn) {
arr = defaultArr();
} else if (defaultArr != null) {
arr = defaultArr;
}
// Leave it up to `cast()` to convert the array
return arr;
});
}
}n/a
function SchemaBoolean(path, options) {
SchemaType.call(this, path, options, 'Boolean');
}n/a
function Document(obj, schema, fields, skipId, skipInit) {
if (!(this instanceof Document)) {
return new Document(obj, schema, fields, skipId, skipInit);
}
if (utils.isObject(schema) && !schema.instanceOfSchema) {
schema = new Schema(schema);
}
// When creating EmbeddedDocument, it already has the schema and he doesn't need the _id
schema = this.schema || schema;
// Generate ObjectId if it is missing, but it requires a scheme
if (!this.schema && schema.options._id) {
obj = obj || {};
if (obj._id === undefined) {
obj._id = new ObjectId();
}
}
if (!schema) {
throw new MongooseError.MissingSchemaError();
}
this.$__setSchema(schema);
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = this.schema.options && this.schema.options.strict;
this.$__.selected = fields;
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
// apply methods
for (var m in schema.methods) {
this[m] = schema.methods[m];
}
// apply statics
for (var s in schema.statics) {
this[s] = schema.statics[s];
}
}n/a
function MissingSchemaError() {
var msg = 'Schema hasn\'t been registered for document.\n'
+ 'Use mongoose.Document(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
}n/a
function SchemaBuffer(key, options) {
SchemaType.call(this, key, options, 'Buffer');
}n/a
function Collection(name, conn, opts) {
if (opts === void 0) {
opts = {};
}
if (opts.capped === void 0) {
opts.capped = {};
}
opts.bufferCommands = undefined === opts.bufferCommands
? true
: opts.bufferCommands;
if (typeof opts.capped === 'number') {
opts.capped = {size: opts.capped};
}
this.opts = opts;
this.name = name;
this.collectionName = name;
this.conn = conn;
this.queue = [];
this.buffer = this.opts.bufferCommands;
this.emitter = new EventEmitter();
if (STATES.connected === this.conn.readyState) {
this.onOpen();
}
}...
model.prototype.$__setSchema(schema);
var collectionOptions = {
bufferCommands: schema.options.bufferCommands,
capped: schema.options.capped
};
model.prototype.collection = connection.collection(
collectionName
, collectionOptions
);
// apply methods and statics
applyMethods(model, schema);
applyStatics(model, schema);
...function Connection(base) {
this.base = base;
this.collections = {};
this.models = {};
this.config = {autoIndex: true};
this.replica = false;
this.hosts = null;
this.host = null;
this.port = null;
this.user = null;
this.pass = null;
this.name = null;
this.options = null;
this.otherDbs = [];
this._readyState = STATES.disconnected;
this._closeCalled = false;
this._hasOpened = false;
}n/a
function SchemaDate(key, options) {
SchemaType.call(this, key, options, 'Date');
}n/a
function Decimal128(key, options) {
SchemaType.call(this, key, options, 'Decimal128');
}n/a
function DisconnectedError(connectionString) {
MongooseError.call(this, 'Ran out of retries trying to reconnect to "' +
connectionString + '". Try setting `server.reconnectTries` and ' +
'`server.reconnectInterval` to something higher.');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'DisconnectedError';
}n/a
function DivergentArrayError(paths) {
var msg = 'For your own good, using `document.save()` to update an array '
+ 'which was selected using an $elemMatch projection OR '
+ 'populated using skip, limit, query conditions, or exclusion of '
+ 'the _id field when the operation results in a $pop or $set of '
+ 'the entire array is not supported. The following '
+ 'path(s) would have been modified unsafely:\n'
+ ' ' + paths.join('\n ') + '\n'
+ 'Use Model.update() to update these arrays instead.';
// TODO write up a docs page (FAQ) and link to it
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'DivergentArrayError';
}n/a
function Document(obj, fields, skipId) {
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
var schema = this.schema;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = schema.options && schema.options.strict;
this.$__.selected = fields;
}
var required = schema.requiredPaths(true);
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (obj) {
if (obj instanceof Document) {
this.isNew = obj.isNew;
}
// Skip set hooks
if (this.$__original_set) {
this.$__original_set(obj, undefined, true);
} else {
this.set(obj, undefined, true);
}
}
if (!schema.options.strict && obj) {
var _this = this,
keys = Object.keys(this._doc);
keys.forEach(function(key) {
if (!(key in schema.tree)) {
defineKey(key, null, _this);
}
});
}
applyQueue(this);
}n/a
function DocumentArray(key, schema, options) {
var EmbeddedDocument = _createConstructor(schema, options);
ArrayType.call(this, key, EmbeddedDocument, options);
this.schema = schema;
this.$isMongooseDocumentArray = true;
var fn = this.defaultValue;
if (!('defaultValue' in this) || fn !== void 0) {
this.default(function() {
var arr = fn.call(this);
if (!Array.isArray(arr)) {
arr = [arr];
}
// Leave it up to `cast()` to convert this to a documentarray
return arr;
});
}
}n/a
function Embedded(schema, path, options) {
var _embedded = function SingleNested(value, path, parent) {
var _this = this;
Subdocument.apply(this, arguments);
this.$parent = parent;
if (parent) {
parent.on('save', function() {
_this.emit('save', _this);
_this.constructor.emit('save', _this);
});
parent.on('isNew', function(val) {
_this.isNew = val;
_this.emit('isNew', val);
_this.constructor.emit('isNew', val);
});
}
};
_embedded.prototype = Object.create(Subdocument.prototype);
_embedded.prototype.$__setSchema(schema);
_embedded.prototype.constructor = _embedded;
_embedded.schema = schema;
_embedded.$isSingleNested = true;
_embedded.prototype.$basePath = path;
_embedded.prototype.toBSON = function() {
return this.toObject({
transform: false,
retainKeyOrder: schema.options.retainKeyOrder,
virtuals: false,
_skipDepopulateTopLevel: true,
depopulate: true,
flattenDecimals: false
});
};
// apply methods
for (var i in schema.methods) {
_embedded.prototype[i] = schema.methods[i];
}
// apply statics
for (i in schema.statics) {
_embedded[i] = schema.statics[i];
}
for (i in EventEmitter.prototype) {
_embedded[i] = EventEmitter.prototype[i];
}
applyHooks(_embedded, schema);
this.caster = _embedded;
this.schema = schema;
this.$isSingleNested = true;
SchemaType.call(this, path, options, 'Embedded');
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
});
req.resume();
}).listen(8088);
...function MissingSchemaError(name) {
var msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
+ 'Use mongoose.model(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
}n/a
function Mixed(path, options) {
if (options && options.default) {
var def = options.default;
if (Array.isArray(def) && def.length === 0) {
// make sure empty array defaults are handled
options.default = Array;
} else if (!options.shared && utils.isObject(def) && Object.keys(def).length === 0) {
// prevent odd "shared" objects between documents
options.default = function() {
return {};
};
}
}
SchemaType.call(this, path, options, 'Mixed');
}n/a
function Model(doc, fields, skipId) {
Document.call(this, doc, fields, skipId, true);
}...
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we
can access it through the same function
```js
var myModel = mongoose.model('ModelName');
```
Or just do it all at once
...function DocumentNotFoundError(query) {
MongooseError.call(this, 'No document found for query "' +
util.inspect(query) + '"');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'DocumentNotFoundError';
this.query = query;
}n/a
function SchemaNumber(key, options) {
SchemaType.call(this, key, options, 'Number');
}n/a
function ObjectExpectedError(path, val) {
MongooseError.call(this, 'Tried to set nested object field `' + path +
'` to primitive value `' + val + '` and strict mode is set to throw.');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ObjectExpectedError';
this.path = path;
}n/a
function ObjectId(key, options) {
SchemaType.call(this, key, options, 'ObjectID');
}n/a
function OverwriteModelError(name) {
MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'OverwriteModelError';
}n/a
function Promise(fn) {
MPromise.call(this, fn);
}n/a
function Query(conditions, options, model, collection) {
// this stuff is for dealing with custom queries created by #toConstructor
if (!this._mongooseOptions) {
this._mongooseOptions = {};
}
// this is the case where we have a CustomQuery, we need to check if we got
// options passed in, and if we did, merge them in
if (options) {
var keys = Object.keys(options);
for (var i = 0; i < keys.length; ++i) {
var k = keys[i];
this._mongooseOptions[k] = options[k];
}
}
if (collection) {
this.mongooseCollection = collection;
}
if (model) {
this.model = model;
this.schema = model.schema;
}
// this is needed because map reduce returns a model that can be queried, but
// all of the queries on said model should be lean
if (this.model && this.model._mapreduce) {
this.lean();
}
// inherit mquery
mquery.call(this, this.mongooseCollection, options);
if (conditions) {
this.find(conditions);
}
if (this.schema) {
var kareemOptions = {
useErrorHandlers: true,
numCallbackParams: 1
};
this._count = this.model.hooks.createWrapper('count',
Query.prototype._count, this, kareemOptions);
this._execUpdate = this.model.hooks.createWrapper('update',
Query.prototype._execUpdate, this, kareemOptions);
this._find = this.model.hooks.createWrapper('find',
Query.prototype._find, this, kareemOptions);
this._findOne = this.model.hooks.createWrapper('findOne',
Query.prototype._findOne, this, kareemOptions);
this._findOneAndRemove = this.model.hooks.createWrapper('findOneAndRemove',
Query.prototype._findOneAndRemove, this, kareemOptions);
this._findOneAndUpdate = this.model.hooks.createWrapper('findOneAndUpdate',
Query.prototype._findOneAndUpdate, this, kareemOptions);
this._replaceOne = this.model.hooks.createWrapper('replaceOne',
Query.prototype._replaceOne, this, kareemOptions);
this._updateMany = this.model.hooks.createWrapper('updateMany',
Query.prototype._updateMany, this, kareemOptions);
this._updateOne = this.model.hooks.createWrapper('updateOne',
Query.prototype._updateOne, this, kareemOptions);
}
}n/a
function QueryCursor(query, options) {
Readable.call(this, { objectMode: true });
this.cursor = null;
this.query = query;
this._transforms = options.transform ? [options.transform] : [];
var _this = this;
var model = query.model;
model.hooks.execPre('find', query, function() {
model.collection.find(query._conditions, options, function(err, cursor) {
if (_this._error) {
cursor.close(function() {});
_this.listeners('error').length > 0 && _this.emit('error', _this._error);
}
if (err) {
return _this.emit('error', err);
}
_this.cursor = cursor;
_this.emit('cursor', cursor);
});
});
}n/a
function QueryStream(query, options) {
Stream.call(this);
this.query = query;
this.readable = true;
this.paused = false;
this._cursor = null;
this._destroyed = null;
this._fields = null;
this._buffer = null;
this._inline = T_INIT;
this._running = false;
this._transform = options && typeof options.transform === 'function'
? options.transform
: K;
// give time to hook up events
var _this = this;
process.nextTick(function() {
_this._init();
});
}n/a
function Schema(obj, options) {
if (!(this instanceof Schema)) {
return new Schema(obj, options);
}
this.obj = obj;
this.paths = {};
this.subpaths = {};
this.virtuals = {};
this.singleNestedPaths = {};
this.nested = {};
this.inherits = {};
this.callQueue = [];
this._indexes = [];
this.methods = {};
this.statics = {};
this.tree = {};
this.query = {};
this.childSchemas = [];
this.s = {
hooks: new Kareem(),
kareemHooks: IS_KAREEM_HOOK
};
this.options = this.defaultOptions(options);
// build paths
if (obj) {
this.add(obj);
}
// check if _id's value is a subdocument (gh-2276)
var _idSubDoc = obj && obj._id && utils.isObject(obj._id);
// ensure the documents get an auto _id unless disabled
var auto_id = !this.paths['_id'] &&
(!this.options.noId && this.options._id) && !_idSubDoc;
if (auto_id) {
obj = {_id: {auto: true}};
obj._id[this.options.typeKey] = Schema.ObjectId;
this.add(obj);
}
// ensure the documents receive an id getter unless disabled
var autoid = !this.paths['id'] &&
(!this.options.noVirtualId && this.options.id);
if (autoid) {
this.virtual('id').get(idGetter);
}
for (var i = 0; i < this._defaultMiddleware.length; ++i) {
var m = this._defaultMiddleware[i];
this[m.kind](m.hook, !!m.isAsync, m.fn);
}
if (this.options.timestamps) {
this.setupTimestamp(this.options.timestamps);
}
}n/a
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] && typeof this[i] === 'function') {
// { unique: true, index: true }
if (i === 'index' && this._index) {
continue;
}
var opts = Array.isArray(options[i])
? options[i]
: [options[i]];
this[i].apply(this, opts);
}
}
}n/a
function StateMachine() {
}n/a
function StrictModeError(path, msg) {
msg = msg || 'Field `' + path + '` is not in schema and strict ' +
'mode is set to throw.';
MongooseError.call(this, msg);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'StrictModeError';
this.path = path;
}n/a
function SchemaString(key, options) {
this.enumValues = [];
this.regExp = null;
SchemaType.call(this, key, options, 'String');
}n/a
function Subdocument(value, fields) {
this.$isSingleNested = true;
Document.call(this, value, fields);
}n/a
function ValidationError(instance) {
this.errors = {};
if (instance && instance.constructor.name === 'model') {
MongooseError.call(this, instance.constructor.modelName + ' validation failed');
} else {
MongooseError.call(this, 'Validation failed');
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ValidationError';
if (instance) {
instance.errors = this.errors;
}
}n/a
function ValidatorError(properties) {
var msg = properties.message;
if (!msg) {
msg = MongooseError.messages.general.default;
}
var message = this.formatMessage(msg, properties);
MongooseError.call(this, message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.properties = properties;
this.name = 'ValidatorError';
this.kind = properties.type;
this.path = properties.path;
this.value = properties.value;
this.reason = properties.reason;
}n/a
function VersionError(doc) {
MongooseError.call(this, 'No matching document found for id "' + doc._id +
'"');
this.name = 'VersionError';
}n/a
function VirtualType(options, name) {
this.path = name;
this.getters = [];
this.setters = [];
this.options = options || {};
}n/a
function ES6Promise() {
throw new Error('Can\'t use ES6 promise with mpromise style constructor');
}n/a
use = function (Promise) {
ES6Promise.ES6 = Promise;
}...
*/
Promise.set = function(lib) {
if (lib === MPromise) {
return Promise.reset();
}
Promise._promise = require('./ES6Promise');
Promise._promise.use(lib);
require('mquery').Promise = Promise._promise.ES6;
};
/**
* Resets to using mpromise
*
* @api private
...function Aggregate() {
this._pipeline = [];
this._model = undefined;
this.options = undefined;
if (arguments.length === 1 && util.isArray(arguments[0])) {
this.append.apply(this, arguments[0]);
} else {
this.append.apply(this, arguments);
}
}...
* ####Example:
*
* new Aggregate();
* new Aggregate({ $project: { a: 1, b: 1 } });
* new Aggregate({ $project: { a: 1, b: 1 } }, { $skip: 5 });
* new Aggregate([{ $project: { a: 1, b: 1 } }, { $skip: 5 }]);
*
* Returned when calling Model.aggregate().
*
* ####Example:
*
* Model
* .aggregate({ $match: { age: { $gte: 21 }}})
* .unwind('tags')
* .exec(callback)
...addCursorFlag = function (flag, value) {
if (!this.options) {
this.options = {};
}
this.options[flag] = value;
return this;
}...
};
/**
* Adds a [cursor flag](http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html#addCursorFlag)
*
* ####Example:
*
* Model.aggregate(..).addCursorFlag('noCursorTimeout', true).exec();
*
* @param {String} flag
* @param {Boolean} value
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html#addCursorFlag
*/
Aggregate.prototype.addCursorFlag = function(flag, value) {
...allowDiskUse = function (value) {
if (!this.options) {
this.options = {};
}
this.options.allowDiskUse = value;
return this;
}...
};
/**
* Sets the allowDiskUse option for the aggregation query (ignored for < 2.6.0)
*
* ####Example:
*
* Model.aggregate(..).allowDiskUse(true).exec(callback)
*
* @param {Boolean} value Should tell server it can use hard drive to store data during aggregation.
* @param {Array} [tags] optional tags for this query
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
*/
Aggregate.prototype.allowDiskUse = function(value) {
...append = function () {
var args = (arguments.length === 1 && util.isArray(arguments[0]))
? arguments[0]
: utils.args(arguments);
if (!args.every(isOperator)) {
throw new Error('Arguments must be aggregate pipeline operators');
}
this._pipeline = this._pipeline.concat(args);
return this;
}...
};
/**
* Appends new operators to this aggregate pipeline
*
* ####Examples:
*
* aggregate.append({ $project: { field: 1 }}, { $limit: 2 });
*
* // or pass an array
* var pipeline = [{ $match: { daw: 'Logic Audio X' }} ];
* aggregate.append(pipeline);
*
* @param {Object} ops operator(s) to append
* @return {Aggregate}
...collation = function (collation) {
if (!this.options) {
this.options = {};
}
this.options.collation = collation;
return this;
}...
};
/**
* Adds a collation
*
* ####Example:
*
* Model.aggregate(..).collation({ locale: 'en_US', strength: 1 }).exec
();
*
* @param {Object} collation options
* @param {Boolean} value
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#aggregate
*/
Aggregate.prototype.collation = function(collation) {
...cursor = function (options) {
if (!this.options) {
this.options = {};
}
this.options.cursor = options || {};
return this;
}...
/**
* Sets the cursor option option for the aggregation query (ignored for < 2.6.0).
* Note the different syntax below: .exec() returns a cursor object, and no callback
* is necessary.
*
* ####Example:
*
* var cursor = Model.aggregate(..).cursor({ batchSize: 1000 }).exec();
* cursor.each(function(error, doc) {
* // use doc
* });
*
* @param {Object} options set the cursor batch size
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.0/api/AggregationCursor.html
*/
...exec = function (callback) {
if (!this._model) {
throw new Error('Aggregate not bound to any Model');
}
var _this = this;
var Promise = PromiseProvider.get();
var options = utils.clone(this.options);
if (options && options.cursor) {
if (options.cursor.async) {
delete options.cursor.async;
return new Promise.ES6(function(resolve) {
if (!_this._model.collection.buffer) {
process.nextTick(function() {
var cursor = _this._model.collection.
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
return;
}
_this._model.collection.emitter.once('queue', function() {
var cursor = _this._model.collection.
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
});
}
var cursor = this._model.collection.
aggregate(this._pipeline, this.options || {});
decorateCursor(cursor);
return cursor;
}
return new Promise.ES6(function(resolve, reject) {
if (!_this._pipeline.length) {
var err = new Error('Aggregate has empty pipeline');
if (callback) {
callback(err);
}
reject(err);
return;
}
prepareDiscriminatorPipeline(_this);
_this._model
.collection
.aggregate(_this._pipeline, _this.options || {}, function(error, result) {
if (error) {
if (callback) {
callback(error);
}
reject(error);
return;
}
if (callback) {
callback(null, result);
}
resolve(result);
});
});
}...
function getVersion() {
var hist = fs.readFileSync('./History.md', 'utf8').replace(/\r/g, '\n').split('\n');
for (var i = 0; i < hist.length; ++i) {
var line = (hist[i] || '').trim();
if (!line) {
continue;
}
var match = /^\s*([^\s]+)\s/.exec(line);
if (match && match[1]) {
return match[1];
}
}
throw new Error('no match found');
}
...explain = function (callback) {
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
if (!_this._pipeline.length) {
var err = new Error('Aggregate has empty pipeline');
if (callback) {
callback(err);
}
reject(err);
return;
}
prepareDiscriminatorPipeline(_this);
_this._model
.collection
.aggregate(_this._pipeline, _this.options || {})
.explain(function(error, result) {
if (error) {
if (callback) {
callback(error);
}
reject(error);
return;
}
if (callback) {
callback(null, result);
}
resolve(result);
});
});
}...
};
/**
* Execute the aggregation with explain
*
* ####Example:
*
* Model.aggregate(..).explain(callback)
*
* @param {Function} callback
* @return {Promise}
*/
Aggregate.prototype.explain = function(callback) {
var _this = this;
...facet = function (options) {
return this.append({$facet: options});
}...
};
/**
* Combines multiple aggregation pipelines.
*
* ####Example:
* Model.aggregate(...)
* .facet({
* books: [{ groupBy: '$author' }],
* price: [{ $bucketAuto: { groupBy: '$price', buckets: 2 } }]
* })
* .exec();
*
* // Output: { books: [...], price: [{...}, {...}] }
*
...graphLookup = function (options) {
var cloneOptions = {};
if (options) {
if (!utils.isObject(options)) {
throw new TypeError('Invalid graphLookup() argument. Must be an object.');
}
utils.mergeClone(cloneOptions, options);
var startWith = cloneOptions.startWith;
if (startWith && typeof startWith === 'string') {
cloneOptions.startWith = cloneOptions.startWith.charAt(0) === '$' ?
cloneOptions.startWith :
'$' + cloneOptions.startWith;
}
}
return this.append({ $graphLookup: cloneOptions });
}...
/**
* Appends new custom $graphLookup operator(s) to this aggregate pipeline, performing a recursive search on a collection.
*
* Note that graphLookup can only consume at most 100MB of memory, and does not allow disk use even if `{ allowDiskUse: true }` is
specified.
*
* #### Examples:
* // Suppose we have a collection of courses, where a document might look like `{ _id: 0, name: 'Calculus', prerequisite
: 'Trigonometry'}` and `{ _id: 0, name: 'Trigonometry', prerequisite: 'Algebra' }`
* aggregate.graphLookup({ from: 'courses', startWith: '$prerequisite
', connectFromField: 'prerequisite', connectToField: 'name', as: 'prerequisites', maxDepth: 3
}) // this will recursively search the 'courses' collection up to 3 prerequisites
*
* @see $graphLookup https://docs.mongodb.com/manual/reference/operator/aggregation/graphLookup/#pipe._S_graphLookup
* @param {Object} options to $graphLookup as described in the above link
* @return {Aggregate}
* @api public
*/
...group = function (arg) {
var op = {};
op['$' + $operator] = arg;
return this.append(op);
}...
};
/**
* Appends a new custom $group operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.group({ _id: "$department" });
*
* @see $group http://docs.mongodb.org/manual/reference/aggregation/group/
* @method group
* @memberOf Aggregate
* @param {Object} arg $group operator contents
* @return {Aggregate}
* @api public
...limit = function (arg) {
var op = {};
op['$' + $operator] = arg;
return this.append(op);
}...
*/
/**
* Appends a new $limit operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.limit(10);
*
* @see $limit http://docs.mongodb.org/manual/reference/aggregation/limit/
* @method limit
* @memberOf Aggregate
* @param {Number} num maximum number of records to pass to the next stage
* @return {Aggregate}
* @api public
...lookup = function (options) {
return this.append({$lookup: options});
}...
};
/**
* Appends new custom $lookup operator(s) to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.lookup({ from: 'users', localField: 'userId', foreignField
: '_id', as: 'users' });
*
* @see $lookup https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/#pipe._S_lookup
* @param {Object} options to $lookup as described in the above link
* @return {Aggregate}
* @api public
*/
...match = function (arg) {
var op = {};
op['$' + $operator] = arg;
return this.append(op);
}...
*/
/**
* Appends a new custom $match operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.match({ department: { $in: [ "sales", "engineering"
; ] } });
*
* @see $match http://docs.mongodb.org/manual/reference/aggregation/match/
* @method match
* @memberOf Aggregate
* @param {Object} arg $match operator contents
* @return {Aggregate}
* @api public
...model = function (model) {
this._model = model;
return this;
}...
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we
can access it through the same function
```js
var myModel = mongoose.model('ModelName');
```
Or just do it all at once
...near = function (arg) {
var op = {};
op.$geoNear = arg;
return this.append(op);
}...
*
* ####NOTE:
*
* **MUST** be used as the first operator in the pipeline.
*
* ####Examples:
*
* aggregate.near({
* near: [40.724, -73.997],
* distanceField: "dist.calculated", // required
* maxDistance: 0.008,
* query: { type: "public" },
* includeLocs: "dist.location",
* uniqueDocs: true,
* num: 5
...out = function (arg) {
var op = {};
op['$' + $operator] = arg;
return this.append(op);
}n/a
project = function (arg) {
var fields = {};
if (typeof arg === 'object' && !util.isArray(arg)) {
Object.keys(arg).forEach(function(field) {
fields[field] = arg[field];
});
} else if (arguments.length === 1 && typeof arg === 'string') {
arg.split(/\s+/).forEach(function(field) {
if (!field) {
return;
}
var include = field[0] === '-' ? 0 : 1;
if (include === 0) {
field = field.substring(1);
}
fields[field] = include;
});
} else {
throw new Error('Invalid project() argument. Must be string or object');
}
return this.append({$project: fields});
}...
* Appends a new $project operator to this aggregate pipeline.
*
* Mongoose query [selection syntax](#query_Query-select) is also supported.
*
* ####Examples:
*
* // include a, include b, exclude _id
* aggregate.project("a b -_id");
*
* // or you may use object notation, useful when
* // you have keys already prefixed with a "-"
* aggregate.project({a: 1, b: 1, _id: 0});
*
* // reshaping documents
* aggregate.project({
...read = function (pref, tags) {
if (!this.options) {
this.options = {};
}
read.call(this, pref, tags);
return this;
}...
};
/**
* Sets the readPreference option for the aggregation query.
*
* ####Example:
*
* Model.aggregate(..).read('primaryPreferred').exec(callback)
*
* @param {String} pref one of the listed preference options or their aliases
* @param {Array} [tags] optional tags for this query
* @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
* @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences
*/
...sample = function (size) {
return this.append({$sample: {size: size}});
}...
};
/**
* Appepnds new custom $sample operator(s) to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.sample(3); // Add a pipeline that picks 3 random documents
*
* @see $sample https://docs.mongodb.org/manual/reference/operator/aggregation/sample/#pipe._S_sample
* @param {Number} size number of random documents to pick
* @return {Aggregate}
* @api public
*/
...skip = function (arg) {
var op = {};
op['$' + $operator] = arg;
return this.append(op);
}...
*/
/**
* Appends a new $skip operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.skip(10);
*
* @see $skip http://docs.mongodb.org/manual/reference/aggregation/skip/
* @method skip
* @memberOf Aggregate
* @param {Number} num number of records to skip before next stage
* @return {Aggregate}
* @api public
...sort = function (arg) {
// TODO refactor to reuse the query builder logic
var sort = {};
if (arg.constructor.name === 'Object') {
var desc = ['desc', 'descending', -1];
Object.keys(arg).forEach(function(field) {
sort[field] = desc.indexOf(arg[field]) === -1 ? 1 : -1;
});
} else if (arguments.length === 1 && typeof arg === 'string') {
arg.split(/\s+/).forEach(function(field) {
if (!field) {
return;
}
var ascend = field[0] === '-' ? -1 : 1;
if (ascend === -1) {
field = field.substring(1);
}
sort[field] = ascend;
});
} else {
throw new TypeError('Invalid sort() argument. Must be a string or object.');
}
return this.append({$sort: sort});
}...
* If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
*
* If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path
name is prefixed with `-` which will be treated as descending.
*
* ####Examples:
*
* // these are equivalent
* aggregate.sort({ field: 'asc', test: -1 });
* aggregate.sort('field -test');
*
* @see $sort http://docs.mongodb.org/manual/reference/aggregation/sort/
* @param {Object|String} arg
* @return {Aggregate} this
* @api public
*/
...then = function (resolve, reject) {
return this.exec().then(resolve, reject);
}...
*
* ####Example:
*
* aggregate.exec(callback);
*
* // Because a promise is returned, the `callback` is optional.
* var promise = aggregate.exec();
* promise.then(..);
*
* @see Promise #promise_Promise
* @param {Function} [callback]
* @return {Promise}
* @api public
*/
...unwind = function () {
var args = utils.args(arguments);
var res = [];
for (var i = 0; i < args.length; ++i) {
var arg = args[i];
if (arg && typeof arg === 'object') {
res.push({ $unwind: arg });
} else if (typeof arg === 'string') {
res.push({
$unwind: (arg && arg.charAt(0) === '$') ? arg : '$' + arg
});
} else {
throw new Error('Invalid arg "' + arg + '" to unwind(), ' +
'must be string or object');
}
}
return this.append.apply(this, res);
}...
*
* Returned when calling Model.aggregate().
*
* ####Example:
*
* Model
* .aggregate({ $match: { age: { $gte: 21 }}})
* .unwind('tags')
* .exec(callback)
*
* ####Note:
*
* - The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).
* - Requires MongoDB >= 2.1
* - Mongoose does **not** cast pipeline stages. `new Aggregate({ $match: { _id: '00000000000000000000000a' } });` will
not work unless `_id` is a string in the database. Use `new Aggregate({ $match: { _id: mongoose.Types.ObjectId('00000000000000000000000a
') } });` instead.
...function SchemaArray(key, cast, options, schemaOptions) {
var typeKey = 'type';
if (schemaOptions && schemaOptions.typeKey) {
typeKey = schemaOptions.typeKey;
}
if (cast) {
var castOptions = {};
if (utils.getFunctionName(cast.constructor) === 'Object') {
if (cast[typeKey]) {
// support { type: Woot }
castOptions = utils.clone(cast); // do not alter user arguments
delete castOptions[typeKey];
cast = cast[typeKey];
} else {
cast = Mixed;
}
}
// support { type: 'String' }
var name = typeof cast === 'string'
? cast
: utils.getFunctionName(cast);
var caster = name in Types
? Types[name]
: cast;
this.casterConstructor = caster;
if (typeof caster === 'function') {
this.caster = new caster(null, castOptions);
} else {
this.caster = caster;
}
if (!(this.caster instanceof EmbeddedDoc)) {
this.caster.path = key;
}
}
SchemaType.call(this, key, options, 'Array');
var defaultArr;
var fn;
if (this.defaultValue != null) {
defaultArr = this.defaultValue;
fn = typeof defaultArr === 'function';
}
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
this.default(function() {
var arr = [];
if (fn) {
arr = defaultArr();
} else if (defaultArr != null) {
arr = defaultArr;
}
// Leave it up to `cast()` to convert the array
return arr;
});
}
}n/a
applyGetters = function (value, scope) {
if (this.caster.options && this.caster.options.ref) {
// means the object id was populated
return value;
}
return SchemaType.prototype.applyGetters.call(this, value, scope);
}...
if (adhoc) {
obj = adhoc.cast(obj);
}
// Check if this path is populated - don't apply getters if it is,
// because otherwise its a nested object. See gh-3357
if (schema && !this.populated(path)) {
obj = schema.applyGetters(obj, this);
}
return obj;
};
/**
* Returns the schematype for the given `path`.
...cast = function (value, doc, init) {
if (Array.isArray(value)) {
if (!value.length && doc) {
var indexes = doc.schema.indexedPaths();
for (var i = 0, l = indexes.length; i < l; ++i) {
var pathIndex = indexes[i][0][this.path];
if (pathIndex === '2dsphere' || pathIndex === '2d') {
return;
}
}
}
if (!(value && value.isMongooseArray)) {
value = new MongooseArray(value, this.path, doc);
} else if (value && value.isMongooseArray) {
// We need to create a new array, otherwise change tracking will
// update the old doc (gh-4449)
value = new MongooseArray(value, this.path, doc);
}
if (this.caster) {
try {
for (i = 0, l = value.length; i < l; i++) {
value[i] = this.caster.cast(value[i], doc, init);
}
} catch (e) {
// rethrow
throw new CastError('[' + e.kind + ']', util.inspect(value), this.path, e);
}
}
return value;
}
// gh-2442: if we're loading this from the db and its not an array, mark
// the whole array as modified.
if (!!doc && !!init) {
doc.markModified(this.path);
}
return this.cast([value], doc, init);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, value) {
var handler,
val;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with Array.');
}
val = handler.call(this, value);
} else {
val = $conditional;
var Constructor = this.casterConstructor;
if (val &&
Constructor.discriminators &&
Constructor.schema.options.discriminatorKey &&
typeof val[Constructor.schema.options.discriminatorKey] === 'string' &&
Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]]) {
Constructor = Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]];
}
var proto = this.casterConstructor.prototype;
var method = proto && (proto.castForQuery || proto.cast);
if (!method && Constructor.castForQuery) {
method = Constructor.castForQuery;
}
var caster = this.caster;
if (Array.isArray(val)) {
val = val.map(function(v) {
if (utils.isObject(v) && v.$elemMatch) {
return v;
}
if (method) {
v = method.call(caster, v);
return v;
}
if (v != null) {
v = new Constructor(v);
return v;
}
return v;
});
} else if (method) {
val = method.call(caster, val);
} else if (val != null) {
val = new Constructor(val);
}
}
return val;
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...checkRequired = function (value) {
return !!(value && value.length);
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function SchemaArray(key, cast, options, schemaOptions) {
var typeKey = 'type';
if (schemaOptions && schemaOptions.typeKey) {
typeKey = schemaOptions.typeKey;
}
if (cast) {
var castOptions = {};
if (utils.getFunctionName(cast.constructor) === 'Object') {
if (cast[typeKey]) {
// support { type: Woot }
castOptions = utils.clone(cast); // do not alter user arguments
delete castOptions[typeKey];
cast = cast[typeKey];
} else {
cast = Mixed;
}
}
// support { type: 'String' }
var name = typeof cast === 'string'
? cast
: utils.getFunctionName(cast);
var caster = name in Types
? Types[name]
: cast;
this.casterConstructor = caster;
if (typeof caster === 'function') {
this.caster = new caster(null, castOptions);
} else {
this.caster = caster;
}
if (!(this.caster instanceof EmbeddedDoc)) {
this.caster.path = key;
}
}
SchemaType.call(this, key, options, 'Array');
var defaultArr;
var fn;
if (this.defaultValue != null) {
defaultArr = this.defaultValue;
fn = typeof defaultArr === 'function';
}
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
this.default(function() {
var arr = [];
if (fn) {
arr = defaultArr();
} else if (defaultArr != null) {
arr = defaultArr;
}
// Leave it up to `cast()` to convert the array
return arr;
});
}
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function SchemaBoolean(path, options) {
SchemaType.call(this, path, options, 'Boolean');
}n/a
cast = function (value) {
if (value === null) {
return value;
}
if (value === '0') {
return false;
}
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
return !!value;
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = SchemaBoolean.$conditionalHandlers[$conditional];
if (handler) {
return handler.call(this, val);
}
return this.cast(val);
}
return this.cast($conditional);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...checkRequired = function (value) {
return value === true || value === false;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function SchemaBoolean(path, options) {
SchemaType.call(this, path, options, 'Boolean');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function Document(obj, fields, skipId) {
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
var schema = this.schema;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = schema.options && schema.options.strict;
this.$__.selected = fields;
}
var required = schema.requiredPaths(true);
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (obj) {
if (obj instanceof Document) {
this.isNew = obj.isNew;
}
// Skip set hooks
if (this.$__original_set) {
this.$__original_set(obj, undefined, true);
} else {
this.set(obj, undefined, true);
}
}
if (!schema.options.strict && obj) {
var _this = this,
keys = Object.keys(this._doc);
keys.forEach(function(key) {
if (!(key in schema.tree)) {
defineKey(key, null, _this);
}
});
}
applyQueue(this);
}...
* MissingSchema Error constructor.
*
* @inherits MongooseError
*/
function MissingSchemaError() {
var msg = 'Schema hasn\'t been registered for document.\n'
+ 'Use mongoose.Document(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
}
/*!
* Inherits from MongooseError.
...function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}n/a
function Schema(obj, options) {
if (!(this instanceof Schema)) {
return new Schema(obj, options);
}
this.obj = obj;
this.paths = {};
this.subpaths = {};
this.virtuals = {};
this.singleNestedPaths = {};
this.nested = {};
this.inherits = {};
this.callQueue = [];
this._indexes = [];
this.methods = {};
this.statics = {};
this.tree = {};
this.query = {};
this.childSchemas = [];
this.s = {
hooks: new Kareem(),
kareemHooks: IS_KAREEM_HOOK
};
this.options = this.defaultOptions(options);
// build paths
if (obj) {
this.add(obj);
}
// check if _id's value is a subdocument (gh-2276)
var _idSubDoc = obj && obj._id && utils.isObject(obj._id);
// ensure the documents get an auto _id unless disabled
var auto_id = !this.paths['_id'] &&
(!this.options.noId && this.options._id) && !_idSubDoc;
if (auto_id) {
obj = {_id: {auto: true}};
obj._id[this.options.typeKey] = Schema.ObjectId;
this.add(obj);
}
// ensure the documents receive an id getter unless disabled
var autoid = !this.paths['id'] &&
(!this.options.noVirtualId && this.options.id);
if (autoid) {
this.virtual('id').get(idGetter);
}
for (var i = 0; i < this._defaultMiddleware.length; ++i) {
var m = this._defaultMiddleware[i];
this[m.kind](m.hook, !!m.isAsync, m.fn);
}
if (this.options.timestamps) {
this.setupTimestamp(this.options.timestamps);
}
}...
* - [Date](#schema-date-js)
* - [ObjectId](#schema-objectid-js) | Oid
* - [Mixed](#schema-mixed-js)
*
* Using this exposed access to the `Mixed` SchemaType, we can use them in our schema.
*
* var Mixed = mongoose.Schema.Types.Mixed;
* new mongoose.Schema({ _user: Mixed })
*
* @api public
*/
Schema.Types = MongooseTypes = require('./schema/index');
/*!
...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] && typeof this[i] === 'function') {
// { unique: true, index: true }
if (i === 'index' && this._index) {
continue;
}
var opts = Array.isArray(options[i])
? options[i]
: [options[i]];
this[i].apply(this, opts);
}
}
}n/a
function VirtualType(options, name) {
this.path = name;
this.getters = [];
this.setters = [];
this.options = options || {};
}n/a
function Document(obj, schema, fields, skipId, skipInit) {
if (!(this instanceof Document)) {
return new Document(obj, schema, fields, skipId, skipInit);
}
if (utils.isObject(schema) && !schema.instanceOfSchema) {
schema = new Schema(schema);
}
// When creating EmbeddedDocument, it already has the schema and he doesn't need the _id
schema = this.schema || schema;
// Generate ObjectId if it is missing, but it requires a scheme
if (!this.schema && schema.options._id) {
obj = obj || {};
if (obj._id === undefined) {
obj._id = new ObjectId();
}
}
if (!schema) {
throw new MongooseError.MissingSchemaError();
}
this.$__setSchema(schema);
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = this.schema.options && this.schema.options.strict;
this.$__.selected = fields;
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
// apply methods
for (var m in schema.methods) {
this[m] = schema.methods[m];
}
// apply statics
for (var s in schema.statics) {
this[s] = schema.statics[s];
}
}n/a
function ValidationError(instance) {
this.errors = {};
if (instance && instance.constructor.name === 'model') {
MongooseError.call(this, instance.constructor.modelName + ' validation failed');
} else {
MongooseError.call(this, 'Validation failed');
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ValidationError';
if (instance) {
instance.errors = this.errors;
}
}n/a
addListener = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}n/a
emit = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}...
You can intercept method arguments via middleware.
For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to
a new value:
```js
schema.pre('set', function (next, path, val, typel) {
// `this` is the current Document
this.emit('set', path, val);
// Pass control to the next pre
next();
});
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments.
To do so, just pass the new values to `next`:
...listeners = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}...
doc[pair[0]].apply(doc, pair[1]);
}
}
}
Document.prototype.$__handleReject = function handleReject(err) {
// emit on the Model if listening
if (this.listeners('error').length) {
this.emit('error', err);
} else if (this.constructor.listeners && this.constructor.listeners('error').length) {
this.constructor.emit('error', err);
} else if (this.listeners && this.listeners('error').length) {
this.emit('error', err);
}
};
...on = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}...
require('http').createServer(function(req, res) {
if (req.url === '/favicon.ico') {
req.destroy();
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
...once = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}...
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
return;
}
_this._model.collection.emitter.once('queue', function() {
var cursor = _this._model.collection.
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
});
...removeAllListeners = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}n/a
removeListener = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}...
}
if (!(value && value.isMongooseDocumentArray) &&
(!options || !options.skipDocumentArrayCast)) {
value = new MongooseDocumentArray(value, this.path, doc);
if (prev && prev._handlers) {
for (var key in prev._handlers) {
doc.removeListener(key, prev._handlers[key]);
}
}
} else if (value && value.isMongooseDocumentArray) {
// We need to create a new array, otherwise change tracking will
// update the old doc (gh-4449)
value = new MongooseDocumentArray(value, this.path, doc);
}
...setMaxListeners = function () {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
}...
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
...function Document(obj, schema, fields, skipId, skipInit) {
if (!(this instanceof Document)) {
return new Document(obj, schema, fields, skipId, skipInit);
}
if (utils.isObject(schema) && !schema.instanceOfSchema) {
schema = new Schema(schema);
}
// When creating EmbeddedDocument, it already has the schema and he doesn't need the _id
schema = this.schema || schema;
// Generate ObjectId if it is missing, but it requires a scheme
if (!this.schema && schema.options._id) {
obj = obj || {};
if (obj._id === undefined) {
obj._id = new ObjectId();
}
}
if (!schema) {
throw new MongooseError.MissingSchemaError();
}
this.$__setSchema(schema);
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = this.schema.options && this.schema.options.strict;
this.$__.selected = fields;
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
// apply methods
for (var m in schema.methods) {
this[m] = schema.methods[m];
}
// apply statics
for (var s in schema.statics) {
this[s] = schema.statics[s];
}
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function MissingSchemaError() {
var msg = 'Schema hasn\'t been registered for document.\n'
+ 'Use mongoose.Document(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function SchemaBuffer(key, options) {
SchemaType.call(this, key, options, 'Buffer');
}n/a
cast = function (value, doc, init) {
var ret;
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (value === null || value === undefined) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (Buffer.isBuffer(value)) {
return value;
} else if (!utils.isObject(value)) {
throw new CastError('buffer', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
// documents
if (value && value._id) {
value = value._id;
}
if (value && value.isMongooseBuffer) {
return value;
}
if (Buffer.isBuffer(value)) {
if (!value || !value.isMongooseBuffer) {
value = new MongooseBuffer(value, [this.path, doc]);
}
return value;
} else if (value instanceof Binary) {
ret = new MongooseBuffer(value.value(true), [this.path, doc]);
if (typeof value.sub_type !== 'number') {
throw new CastError('buffer', value, this.path);
}
ret._subtype = value.sub_type;
return ret;
}
if (value === null) {
return value;
}
var type = typeof value;
if (type === 'string' || type === 'number' || Array.isArray(value)) {
if (type === 'number') {
value = [value];
}
ret = new MongooseBuffer(value, [this.path, doc]);
return ret;
}
throw new CastError('buffer', value, this.path);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with Buffer.');
}
return handler.call(this, val);
}
val = $conditional;
var casted = this.cast(val);
return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...checkRequired = function (value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return !!value;
}
return !!(value && value.length);
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function SchemaBuffer(key, options) {
SchemaType.call(this, key, options, 'Buffer');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function Collection(name, conn, opts) {
if (opts === void 0) {
opts = {};
}
if (opts.capped === void 0) {
opts.capped = {};
}
opts.bufferCommands = undefined === opts.bufferCommands
? true
: opts.bufferCommands;
if (typeof opts.capped === 'number') {
opts.capped = {size: opts.capped};
}
this.opts = opts;
this.name = name;
this.collectionName = name;
this.conn = conn;
this.queue = [];
this.buffer = this.opts.bufferCommands;
this.emitter = new EventEmitter();
if (STATES.connected === this.conn.readyState) {
this.onOpen();
}
}...
model.prototype.$__setSchema(schema);
var collectionOptions = {
bufferCommands: schema.options.bufferCommands,
capped: schema.options.capped
};
model.prototype.collection = connection.collection(
collectionName
, collectionOptions
);
// apply methods and statics
applyMethods(model, schema);
applyStatics(model, schema);
...addQueue = function (name, args) {
this.queue.push([name, args]);
return this;
}...
create();
}));
};
setImmediate(function() {
// If buffering is off, do this manually.
if (options._automatic && !model.collection.collection) {
model.collection.addQueue(create, []);
} else {
create();
}
});
}
function _handleSafe(options) {
...doQueue = function () {
for (var i = 0, l = this.queue.length; i < l; i++) {
if (typeof this.queue[i][0] === 'function') {
this.queue[i][0].apply(this, this.queue[i][1]);
} else {
this[this.queue[i][0]].apply(this, this.queue[i][1]);
}
}
this.queue = [];
var _this = this;
process.nextTick(function() {
_this.emitter.emit('queue');
});
return this;
}...
* Called when the database connects
*
* @api private
*/
Collection.prototype.onOpen = function() {
this.buffer = false;
this.doQueue();
};
/**
* Called when the database disconnects
*
* @api private
*/
...ensureIndex = function () {
throw new Error('Collection#ensureIndex unimplemented by driver');
}...
var indexFields = index[0];
var options = index[1];
_handleSafe(options);
indexSingleStart(indexFields, options);
model.collection.ensureIndex(indexFields, options, utils.tick(function(err, name) {
indexSingleDone(err, indexFields, options, name);
if (err) {
return done(err);
}
create();
}));
};
...find = function () {
throw new Error('Collection#find unimplemented by driver');
}...
//
});
```
Or we can find documents from the same collection
```js
MyModel.find({}, function (err, docs) {
// docs.forEach
});
```
You can also `findOne`, `findById`, `update`, etc. For more details check out [the docs](http://mongoosejs.com/docs/queries.html
).
**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `
mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this
case access your model through the connection you created:
...findAndModify = function () {
throw new Error('Collection#findAndModify unimplemented by driver');
}...
};
if (opts.runValidators && doValidate) {
var _callback = function(error) {
if (error) {
return callback(error);
}
_this._collection.findAndModify(castedQuery, castedDoc, opts, utils.tick(function(error
, res) {
return cb(error, res ? res.value : res, res);
}));
};
try {
doValidate(_callback);
} catch (error) {
...findOne = function () {
throw new Error('Collection#findOne unimplemented by driver');
}...
};
/**
* Checks if `path` was selected in the source query which initialized this document.
*
* ####Example
*
* Thing.findOne().select('name').exec(function (err, doc) {
* doc.isSelected('name') // true
* doc.isSelected('age') // false
* })
*
* @param {String} path
* @return {Boolean}
* @api public
...getIndexes = function () {
throw new Error('Collection#getIndexes unimplemented by driver');
}n/a
insert = function () {
throw new Error('Collection#insert unimplemented by driver');
}...
setTimeout(function() {
callback(new Error('document must have an _id before saving'));
}, 0);
return;
}
this.$__version(true, obj);
this.collection.insert(obj, options.safe, function(err, ret) {
if (err) {
_this.isNew = true;
_this.emit('isNew', true);
_this.constructor.emit('isNew', true);
callback(err);
return;
...mapReduce = function () {
throw new Error('Collection#mapReduce unimplemented by driver');
}...
* `o` is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver
implementation. See [node-mongodb-native mapReduce() documentation](http://mongodb.github.io/node-mongodb-native/api-generated/
collection.html#mapreduce) for more detail about options.
*
* ####Example:
*
* var o = {};
* o.map = function () { emit(this.name, 1) }
* o.reduce = function (k, vals) { return vals.length }
* User.mapReduce(o, function (err, results) {
* console.log(results)
* })
*
* ####Other options:
*
* - `query` {Object} query filter object.
* - `sort` {Object} sort input objects using this key
...onClose = function () {
if (this.opts.bufferCommands) {
this.buffer = true;
}
}...
case 1: // connected
case 4: // unauthorized
this.readyState = STATES.disconnecting;
this.doClose(function(err) {
if (err) {
_this.error(err, callback);
} else {
_this.onClose();
callback && callback();
}
});
break;
case 2: // connecting
this.once('open', function() {
...onOpen = function () {
this.buffer = false;
this.doQueue();
}...
this.collectionName = name;
this.conn = conn;
this.queue = [];
this.buffer = this.opts.bufferCommands;
this.emitter = new EventEmitter();
if (STATES.connected === this.conn.readyState) {
this.onOpen();
}
}
/**
* The collection name
*
* @api public
...save = function () {
throw new Error('Collection#save unimplemented by driver');
}...
Then Mongoose will create the model for your __tickets__ collection, not your __ticket__ collection.
Once we have our model, we can then instantiate it, and save it:
```js
var instance = new MyModel();
instance.my.key = 'hello';
instance.save(function (err) {
//
});
```
Or we can find documents from the same collection
```js
...update = function () {
throw new Error('Collection#update unimplemented by driver');
}...
}
/**
* Sends an update command with this document `_id` as the query selector.
*
* ####Example:
*
* weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback);
*
* ####Valid options:
*
* - same as in [Model.update](#model_Model.update)
*
* @see Model.update #model_Model.update
* @param {Object} doc
...function flatten(update, path, options) {
var keys;
if (update && utils.isMongooseObject(update) && !Buffer.isBuffer(update)) {
keys = Object.keys(update.toObject({ transform: false, virtuals: false }));
} else {
keys = Object.keys(update || {});
}
var numKeys = keys.length;
var result = {};
path = path ? path + '.' : '';
for (var i = 0; i < numKeys; ++i) {
var key = keys[i];
var val = update[key];
result[path + key] = val;
if (shouldFlatten(val)) {
if (options && options.skipArrays && Array.isArray(val)) {
continue;
}
var flat = flatten(val, path + key);
for (var k in flat) {
result[k] = flat[k];
}
if (Array.isArray(val)) {
result[path + key] = val;
}
}
}
return result;
}...
if (mod.options.match) {
match = utils.object.shallowCopy(mod.options.match);
} else {
match = {};
}
var ids = utils.array.flatten(mod.ids, flatten);
ids = utils.array.unique(ids);
if (ids.length === 0 || ids.every(utils.isNullOrUndefined)) {
--_remaining;
continue;
}
...function modifiedPaths(update, path, result) {
var keys = Object.keys(update || {});
var numKeys = keys.length;
result = result || {};
path = path ? path + '.' : '';
for (var i = 0; i < numKeys; ++i) {
var key = keys[i];
var val = update[key];
result[path + key] = true;
if (utils.isMongooseObject(val) && !Buffer.isBuffer(val)) {
val = val.toObject({ transform: false, virtuals: false });
}
if (shouldFlatten(val)) {
modifiedPaths(val, path + key, result);
}
}
return result;
}...
*/
Document.prototype.isModified = function(paths) {
if (paths) {
if (!Array.isArray(paths)) {
paths = paths.split(' ');
}
var modified = this.modifiedPaths();
var directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
var isModifiedChild = paths.some(function(path) {
return !!~modified.indexOf(path);
});
return isModifiedChild || paths.some(function(path) {
return directModifiedPaths.some(function(mod) {
return mod === path || path.indexOf(mod + '.') === 0;
...function Connection(base) {
this.base = base;
this.collections = {};
this.models = {};
this.config = {autoIndex: true};
this.replica = false;
this.hosts = null;
this.host = null;
this.port = null;
this.user = null;
this.pass = null;
this.name = null;
this.options = null;
this.otherDbs = [];
this._readyState = STATES.disconnected;
this._closeCalled = false;
this._hasOpened = false;
}n/a
_close = function (callback) {
var _this = this;
this._closeCalled = true;
switch (this.readyState) {
case 0: // disconnected
callback && callback();
break;
case 1: // connected
case 4: // unauthorized
this.readyState = STATES.disconnecting;
this.doClose(function(err) {
if (err) {
_this.error(err, callback);
} else {
_this.onClose();
callback && callback();
}
});
break;
case 2: // connecting
this.once('open', function() {
_this.close(callback);
});
break;
case 3: // disconnecting
if (!callback) {
break;
}
this.once('close', function() {
callback();
});
break;
}
return this;
}...
* @api public
*/
Connection.prototype.close = function(callback) {
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
_this._close(function(error) {
callback && callback(error);
if (error) {
reject(error);
return;
}
resolve();
});
..._open = function (emit, callback) {
this.readyState = STATES.connecting;
this._closeCalled = false;
var _this = this;
var method = this.replica
? 'doOpenSet'
: 'doOpen';
// open connection
this[method](function(err) {
if (err) {
_this.readyState = STATES.disconnected;
if (_this._hasOpened) {
if (callback) {
callback(err);
}
} else {
_this.error(err, emit && callback);
}
return;
}
_this.onOpen(callback);
});
}...
this.name = database;
this.host = host;
this.port = port;
var _this = this;
var promise = new Promise.ES6(function(resolve, reject) {
_this._open(true, function(error) {
callback && callback(error);
if (error) {
// Error can be on same tick re: christkv/mongodb-core#157
setImmediate(function() {
reject(error);
if (!callback && !promise.$hasHandler) {
_this.emit('error', error);
...authMechanismDoesNotRequirePassword = function () {
if (this.options && this.options.auth) {
return authMechanismsWhichDontRequirePassword.indexOf(this.options.auth.authMechanism) >= 0;
}
return true;
}...
* username and password are both provided than authentication is needed, but in some cases a
* password is not required.
* @api private
* @return {Boolean} true if the connection should be authenticated after it is opened, otherwise false.
*/
Connection.prototype.shouldAuthenticate = function() {
return (this.user !== null && this.user !== void 0) &&
((this.pass !== null || this.pass !== void 0) || this.authMechanismDoesNotRequirePassword
());
};
/**
* @brief Returns a boolean value that specifies if the current authentication mechanism needs a
* password to authenticate according to the auth objects passed into the open/openSet methods.
* @api private
* @return {Boolean} true if the authentication mechanism specified in the options object requires
...close = function (callback) {
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
_this._close(function(error) {
callback && callback(error);
if (error) {
reject(error);
return;
}
resolve();
});
});
}...
* For practical reasons, a Connection equals a Db.
*
* @param {Mongoose} base a mongoose instance
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `connecting`: Emitted when `connection.{open,openSet}()` is executed on this connection.
* @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected
` scenarios.
* @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models.
* @event `disconnecting`: Emitted when `connection.close()` was executed.
* @event `disconnected`: Emitted after getting disconnected from the db.
* @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models.
* @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successfull
connection.
* @event `error`: Emitted when an error occurs on this connection.
* @event `fullsetup`: Emitted in a replica-set scenario, when primary and at least one seconaries specified in the connection string
are connected.
* @event `all`: Emitted in a replica-set scenario, when all nodes specified in the connection string are connected.
* @api public
...collection = function (name, options) {
if (!(name in this.collections)) {
this.collections[name] = new Collection(name, this, options);
}
return this.collections[name];
}...
model.prototype.$__setSchema(schema);
var collectionOptions = {
bufferCommands: schema.options.bufferCommands,
capped: schema.options.capped
};
model.prototype.collection = connection.collection(
collectionName
, collectionOptions
);
// apply methods and statics
applyMethods(model, schema);
applyStatics(model, schema);
...dropDatabase = function (callback) {
var Promise = PromiseProvider.get();
var _this = this;
var promise = new Promise.ES6(function(resolve, reject) {
if (_this.readyState !== STATES.connected) {
_this.on('open', function() {
_this.db.dropDatabase(function(error) {
if (error) {
reject(error);
} else {
resolve();
}
});
});
} else {
_this.db.dropDatabase(function(error) {
if (error) {
reject(error);
} else {
resolve();
}
});
}
});
if (callback) {
promise.then(function() { callback(); }, callback);
}
return promise;
}...
Connection.prototype.dropDatabase = function(callback) {
var Promise = PromiseProvider.get();
var _this = this;
var promise = new Promise.ES6(function(resolve, reject) {
if (_this.readyState !== STATES.connected) {
_this.on('open', function() {
_this.db.dropDatabase(function(error) {
if (error) {
reject(error);
} else {
resolve();
}
});
});
...error = function (err, callback) {
if (callback) {
return callback(err);
}
this.emit('error', err);
}...
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
});
req.resume();
}).listen(8088);
...model = function (name, schema, collection) {
// collection name discovery
if (typeof schema === 'string') {
collection = schema;
schema = false;
}
if (utils.isObject(schema) && !schema.instanceOfSchema) {
schema = new Schema(schema);
}
if (schema && !schema.instanceOfSchema) {
throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
'schema or a POJO');
}
if (this.models[name] && !collection) {
// model exists but we are not subclassing with custom collection
if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
throw new MongooseError.OverwriteModelError(name);
}
return this.models[name];
}
var opts = {cache: false, connection: this};
var model;
if (schema && schema.instanceOfSchema) {
// compile a model
model = this.base.model(name, schema, collection, opts);
// only the first model with this name is cached to allow
// for one-offs with custom collection names etc.
if (!this.models[name]) {
this.models[name] = model;
}
model.init();
return model;
}
if (this.models[name] && collection) {
// subclassing current model with alternate collection
model = this.models[name];
schema = model.prototype.schema;
var sub = model.__subclass(this, schema, collection);
// do not cache the sub model
return sub;
}
// lookup model in mongoose module
model = this.base.models[name];
if (!model) {
throw new MongooseError.MissingSchemaError(name);
}
if (this === model.prototype.db
&& (!collection || collection === model.collection.name)) {
// model already uses this connection.
// only the first model with this name is cached to allow
// for one-offs with custom collection names etc.
if (!this.models[name]) {
this.models[name] = model;
}
return model;
}
this.models[name] = model.__subclass(this, schema, collection);
return this.models[name];
}...
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we
can access it through the same function
```js
var myModel = mongoose.model('ModelName');
```
Or just do it all at once
...modelNames = function () {
return Object.keys(this.models);
}n/a
onClose = function () {
this.readyState = STATES.disconnected;
// avoid having the collection subscribe to our event emitter
// to prevent 0.3 warning
for (var i in this.collections) {
if (utils.object.hasOwnProperty(this.collections, i)) {
this.collections[i].onClose();
}
}
this.emit('close');
}...
case 1: // connected
case 4: // unauthorized
this.readyState = STATES.disconnecting;
this.doClose(function(err) {
if (err) {
_this.error(err, callback);
} else {
_this.onClose();
callback && callback();
}
});
break;
case 2: // connecting
this.once('open', function() {
...onOpen = function (callback) {
var _this = this;
function open(err, isAuth) {
if (err) {
_this.readyState = isAuth ? STATES.unauthorized : STATES.disconnected;
_this.error(err, callback);
return;
}
_this.readyState = STATES.connected;
// avoid having the collection subscribe to our event emitter
// to prevent 0.3 warning
for (var i in _this.collections) {
if (utils.object.hasOwnProperty(_this.collections, i)) {
_this.collections[i].onOpen();
}
}
callback && callback();
_this.emit('open');
}
// re-authenticate if we're not already connected #3871
if (this._readyState !== STATES.connected && this.shouldAuthenticate()) {
_this.db.authenticate(_this.user, _this.pass, _this.options.auth, function(err) {
open(err, true);
});
} else {
open();
}
}...
this.collectionName = name;
this.conn = conn;
this.queue = [];
this.buffer = this.opts.bufferCommands;
this.emitter = new EventEmitter();
if (STATES.connected === this.conn.readyState) {
this.onOpen();
}
}
/**
* The collection name
*
* @api public
...open = function (host, database, port, options, callback) {
var parsed;
var Promise = PromiseProvider.get();
var err;
if (typeof database === 'string') {
switch (arguments.length) {
case 2:
port = 27017;
break;
case 3:
switch (typeof port) {
case 'function':
callback = port;
port = 27017;
break;
case 'object':
options = port;
port = 27017;
break;
}
break;
case 4:
if (typeof options === 'function') {
callback = options;
options = {};
}
}
} else {
switch (typeof database) {
case 'function':
callback = database;
database = undefined;
break;
case 'object':
options = database;
database = undefined;
callback = port;
break;
}
if (!rgxProtocol.test(host)) {
host = 'mongodb://' + host;
}
try {
parsed = muri(host);
} catch (err) {
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
database = parsed.db;
host = parsed.hosts[0].host || parsed.hosts[0].ipc;
port = parsed.hosts[0].port || 27017;
}
this.options = this.parseOptions(options, parsed && parsed.options);
// make sure we can open
if (STATES.disconnected !== this.readyState) {
err = new Error('Trying to open unclosed connection.');
err.state = this.readyState;
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
if (!host) {
err = new Error('Missing hostname.');
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
if (!database) {
err = new Error('Missing database name.');
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
// authentication
if (this.optionsProvideAuthenticationData(options)) {
this.user = options.user;
this.pass = options.pass;
} else if (parsed && parsed.auth) {
this.user = parsed.auth.user;
this.pass = parsed.auth.pass;
// Check hostname for user/pass
} else if (/@/.test(host) && /:/.test(host.split('@')[0])) {
host = host.split('@');
if (host.length > 2) {
err = new Error('Username and password must be URI encoded if they ' +
'contain "@", see http://bit.ly/2nRYRyq');
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
var auth = host.shift().split(':');
if (auth.length > 2) {
err = new Error('Username and password must be URI encoded if they ' +
'contain ":", see http://bit.ly/2nRYRyq');
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
host = host.pop();
this.user = auth[0];
this.pass = auth[1];
} else {
this.user = this.pass = undefined;
}
// global configuration options
if (options && options.config) {
this.config.autoIndex = options.config.autoIndex !== false;
}
this.name = database;
this.host = host;
this.port = port;
var _this = this;
var promise = new Promise.ES6(function(resolve, reject) {
_this._open(true, function(error) {
callback && callback(error);
if (error) {
// Error can be on same tick re: christkv/mongodb-core#157
setImmediate(function() {
reject(error);
if (!callback && !promise.$hasHandler) {
_this.emit('error', error);
}
});
return;
}
resolve();
});
});
return promise;
}...
*
* _Options passed take precedence over options included in connection strings._
*
* ####Notes:
*
* _If connecting to multiple mongos servers, set the `mongos` option to true._
*
* conn.open('mongodb://mongosA:27501,mongosB:27501', { mongos: true },
cb);
*
* 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.
*
* _Options passed take precedence over options included in connection strings._
*
...openSet = function (uris, database, options, callback) {
if (!rgxProtocol.test(uris)) {
uris = 'mongodb://' + uris;
}
var Promise = PromiseProvider.get();
switch (arguments.length) {
case 3:
switch (typeof database) {
case 'string':
this.name = database;
break;
case 'object':
callback = options;
options = database;
database = null;
break;
}
if (typeof options === 'function') {
callback = options;
options = {};
}
break;
case 2:
switch (typeof database) {
case 'string':
this.name = database;
break;
case 'function':
callback = database;
database = null;
break;
case 'object':
options = database;
database = null;
break;
}
}
if (typeof database === 'string') {
this.name = database;
}
var parsed;
try {
parsed = muri(uris);
} catch (err) {
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
if (!this.name) {
this.name = parsed.db;
}
this.hosts = parsed.hosts;
this.options = this.parseOptions(options, parsed && parsed.options);
this.replica = true;
if (!this.name) {
var err = new Error('No database name provided for replica set');
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
// authentication
if (this.optionsProvideAuthenticationData(options)) {
this.user = options.user;
this.pass = options.pass;
} else if (parsed && parsed.auth) {
this.user = parsed.auth.user;
this.pass = parsed.auth.pass;
} else {
this.user = this.pass = undefined;
}
// global configuration options
if (options && options.config) {
this.config.autoIndex = options.config.autoIndex !== false;
}
var _this = this;
var emitted = false;
var promise = new Promise.ES6(function(resolve, reject) {
_this._open(true, function(error) {
callback && callback(error);
if (error) {
reject(error);
if (!callback && !promise.$hasHandler && !emitted) {
emitted = true;
_this.emit('error', error);
}
return;
}
resolve();
});
});
return promise;
}...
/**
* Opens the connection to a replica set.
*
* ####Example:
*
* var db = mongoose.createConnection();
* db.openSet("mongodb://user:pwd@localhost:27020,localhost:27021,localhost:27012
/mydb");
*
* The database name and/or auth need only be included in one URI.
* The `options` is a hash which is passed to the internal driver connection object.
*
* Valid `options`
*
* db - passed to the connection db instance
...optionsProvideAuthenticationData = function (options) {
return (options) &&
(options.user) &&
((options.pass) || this.authMechanismDoesNotRequirePassword());
}...
this.error(err, callback);
return new Promise.ES6(function(resolve, reject) {
reject(err);
});
}
// authentication
if (this.optionsProvideAuthenticationData(options)) {
this.user = options.user;
this.pass = options.pass;
} else if (parsed && parsed.auth) {
this.user = parsed.auth.user;
this.pass = parsed.auth.pass;
// Check hostname for user/pass
...shouldAuthenticate = function () {
return (this.user !== null && this.user !== void 0) &&
((this.pass !== null || this.pass !== void 0) || this.authMechanismDoesNotRequirePassword());
}...
}
callback && callback();
_this.emit('open');
}
// re-authenticate if we're not already connected #3871
if (this._readyState !== STATES.connected && this.shouldAuthenticate()) {
_this.db.authenticate(_this.user, _this.pass, _this.options.auth, function(err) {
open(err, true);
});
} else {
open();
}
};
...function SchemaDate(key, options) {
SchemaType.call(this, key, options, 'Date');
}n/a
cast = function (value) {
// If null or undefined
if (value === null || value === void 0 || value === '') {
return null;
}
if (value instanceof Date) {
if (isNaN(value.valueOf())) {
throw new CastError('date', value, this.path);
}
return value;
}
var date;
if (typeof value === 'boolean') {
throw new CastError('date', value, this.path);
}
if (value instanceof Number || typeof value === 'number'
|| String(value) == Number(value)) {
// support for timestamps
date = new Date(Number(value));
} else if (value.valueOf) {
// support for moment.js
date = new Date(value.valueOf());
}
if (!isNaN(date.valueOf())) {
return date;
}
throw new CastError('date', value, this.path);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length !== 2) {
return this.cast($conditional);
}
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with Date.');
}
return handler.call(this, val);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...checkRequired = function (value) {
return value instanceof Date;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function SchemaDate(key, options) {
SchemaType.call(this, key, options, 'Date');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...expires = function (when) {
if (!this._index || this._index.constructor.name !== 'Object') {
this._index = {};
}
this._index.expires = when;
utils.expires(this._index);
return this;
}...
* @api public
*/
Schema.prototype.index = function(fields, options) {
options || (options = {});
if (options.expires) {
utils.expires(options);
}
this._indexes.push([fields, options]);
return this;
};
/**
...max = function (value, message) {
if (this.maxValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.maxValidator;
}, this);
}
if (value) {
var msg = message || MongooseError.messages.Date.max;
msg = msg.replace(/{MAX}/, (value === Date.now ? 'Date.now()' : this.cast(value).toString()));
var _this = this;
this.validators.push({
validator: this.maxValidator = function(val) {
var max = (value === Date.now ? value() : _this.cast(value));
return val === null || val.valueOf() <= max.valueOf();
},
message: msg,
type: 'max',
max: value
});
}
return this;
}n/a
min = function (value, message) {
if (this.minValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.minValidator;
}, this);
}
if (value) {
var msg = message || MongooseError.messages.Date.min;
msg = msg.replace(/{MIN}/, (value === Date.now ? 'Date.now()' : this.cast(value).toString()));
var _this = this;
this.validators.push({
validator: this.minValidator = function(val) {
var min = (value === Date.now ? value() : _this.cast(value));
return val === null || val.valueOf() >= min.valueOf();
},
message: msg,
type: 'min',
min: value
});
}
return this;
}n/a
function Decimal128(key, options) {
SchemaType.call(this, key, options, 'Decimal128');
}n/a
cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (value === null || value === undefined) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (value instanceof Decimal128Type) {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('Decimal128', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = value;
if (!doc.$__.populated ||
!doc.$__.populated[path] ||
!doc.$__.populated[path].options ||
!doc.$__.populated[path].options.options ||
!doc.$__.populated[path].options.options.lean) {
ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
}
return ret;
}
if (value === null || value === undefined) {
return value;
}
if (value instanceof Decimal128Type) {
return value;
}
if (typeof value === 'string') {
return Decimal128Type.fromString(value);
}
if (Buffer.isBuffer(value)) {
return new Decimal128Type(value);
}
throw new CastError('Decimal128', value, this.path);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with ObjectId.');
}
return handler.call(this, val);
}
return this.cast($conditional);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...function checkRequired(value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return !!value;
}
return value instanceof Decimal128Type;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function Decimal128(key, options) {
SchemaType.call(this, key, options, 'Decimal128');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function DisconnectedError(connectionString) {
MongooseError.call(this, 'Ran out of retries trying to reconnect to "' +
connectionString + '". Try setting `server.reconnectTries` and ' +
'`server.reconnectInterval` to something higher.');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'DisconnectedError';
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function DivergentArrayError(paths) {
var msg = 'For your own good, using `document.save()` to update an array '
+ 'which was selected using an $elemMatch projection OR '
+ 'populated using skip, limit, query conditions, or exclusion of '
+ 'the _id field when the operation results in a $pop or $set of '
+ 'the entire array is not supported. The following '
+ 'path(s) would have been modified unsafely:\n'
+ ' ' + paths.join('\n ') + '\n'
+ 'Use Model.update() to update these arrays instead.';
// TODO write up a docs page (FAQ) and link to it
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'DivergentArrayError';
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function Document(obj, fields, skipId) {
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
var schema = this.schema;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = schema.options && schema.options.strict;
this.$__.selected = fields;
}
var required = schema.requiredPaths(true);
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (obj) {
if (obj instanceof Document) {
this.isNew = obj.isNew;
}
// Skip set hooks
if (this.$__original_set) {
this.$__original_set(obj, undefined, true);
} else {
this.set(obj, undefined, true);
}
}
if (!schema.options.strict && obj) {
var _this = this,
keys = Object.keys(this._doc);
keys.forEach(function(key) {
if (!(key in schema.tree)) {
defineKey(key, null, _this);
}
});
}
applyQueue(this);
}n/a
function ValidationError(instance) {
this.errors = {};
if (instance && instance.constructor.name === 'model') {
MongooseError.call(this, instance.constructor.modelName + ' validation failed');
} else {
MongooseError.call(this, 'Validation failed');
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ValidationError';
if (instance) {
instance.errors = this.errors;
}
}n/a
_lazySetupHooks = function (proto, methodName, errorCb) {
if ('undefined' === typeof proto[methodName].numAsyncPres) {
this.$hook(methodName, proto[methodName], errorCb);
}
}n/a
removePost = function (name, fnToRemove) {
var proto = this.prototype || this
, posts = proto._posts || (proto._posts || {});
if (!posts[name]) return this;
if (arguments.length === 1) {
// Remove all post callbacks for hook `name`
posts[name].length = 0;
} else {
posts[name] = posts[name].filter( function (currFn) {
return currFn !== fnToRemove;
});
}
return this;
}n/a
removePre = function (name, fnToRemove) {
var proto = this.prototype || this
, pres = proto._pres || (proto._pres || {});
if (!pres[name]) return this;
if (arguments.length === 1) {
// Remove all pre callbacks for hook `name`
pres[name].length = 0;
} else {
pres[name] = pres[name].filter( function (currFn) {
return currFn !== fnToRemove;
});
}
return this;
}n/a
_lazySetupHooks = function (proto, methodName, errorCb) {
if ('undefined' === typeof proto[methodName].numAsyncPres) {
this.$hook(methodName, proto[methodName], errorCb);
}
}n/a
addListener = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}n/a
depopulate = function (path) {
var populatedIds = this.populated(path);
if (!populatedIds) {
return;
}
delete this.$__.populated[path];
this.set(path, populatedIds);
return this;
}...
/**
* Takes a populated field and returns it to its unpopulated state.
*
* ####Example:
*
* Model.findOne().populate('author').exec(function (err, doc) {
* console.log(doc.author.name); // Dr.Seuss
* console.log(doc.depopulate('author'));
* console.log(doc.author); // '5144cf8050f071d979c118a7'
* })
*
* If the path was not populated, this is a no-op.
*
* @param {String} path
* @return {Document} this
...emit = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}...
You can intercept method arguments via middleware.
For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to
a new value:
```js
schema.pre('set', function (next, path, val, typel) {
// `this` is the current Document
this.emit('set', path, val);
// Pass control to the next pre
next();
});
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments.
To do so, just pass the new values to `next`:
...equals = function (doc) {
if (!doc) {
return false;
}
var tid = this.get('_id');
var docid = doc.get ? doc.get('_id') : doc;
if (!tid && !docid) {
return deepEqual(this, doc);
}
return tid && tid.equals
? tid.equals(docid)
: tid === docid;
}...
var tid = this.get('_id');
var docid = doc.get ? doc.get('_id') : doc;
if (!tid && !docid) {
return deepEqual(this, doc);
}
return tid && tid.equals
? tid.equals(docid)
: tid === docid;
};
/**
* Populates document references, executing the `callback` when complete.
* If you want to use promises instead, use this function with
* [`execPopulate()`](#document_Document-execPopulate)
...execPopulate = function () {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_this.populate(function(error, res) {
if (error) {
reject(error);
} else {
resolve(res);
}
});
});
}...
*
* // summary
* doc.populate(path) // not executed
* doc.populate(options); // not executed
* doc.populate(path, callback) // executed
* doc.populate(options, callback); // executed
* doc.populate(callback); // executed
* doc.populate(options).execPopulate() // executed, returns promise
*
*
* ####NOTE:
*
* Population does not occur unless a `callback` is passed *or* you explicitly
* call `execPopulate()`.
* Passing the same path a second time will overwrite the previous path options.
...get = function (path, type) {
var adhoc;
if (type) {
adhoc = Schema.interpretAsType(path, type, this.schema.options);
}
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 = obj === null || obj === void 0
? undefined
: obj[pieces[i]];
}
if (adhoc) {
obj = adhoc.cast(obj);
}
// Check if this path is populated - don't apply getters if it is,
// because otherwise its a nested object. See gh-3357
if (schema && !this.populated(path)) {
obj = schema.applyGetters(obj, this);
}
return obj;
}...
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
...getValue = function (path) {
return utils.getValue(path, this._doc);
}...
// If doc._id is not null or undefined
if (doc._id !== null && doc._id !== undefined &&
opts && opts.populated && opts.populated.length) {
var id = String(doc._id);
for (var i = 0; i < opts.populated.length; ++i) {
var item = opts.populated[i];
if (item.isVirtual) {
this.populated(item.path, utils.getValue(item.path, doc), item);
} else {
this.populated(item.path, item._docs[id], item);
}
}
}
init(this, doc, this._doc);
...init = function (doc, opts, fn) {
// do not prefix this method with $__ since its
// used by public hooks
if (typeof opts === 'function') {
fn = opts;
opts = null;
}
this.isNew = false;
// handle docs with populated paths
// If doc._id is not null or undefined
if (doc._id !== null && doc._id !== undefined &&
opts && opts.populated && opts.populated.length) {
var id = String(doc._id);
for (var i = 0; i < opts.populated.length; ++i) {
var item = opts.populated[i];
if (item.isVirtual) {
this.populated(item.path, utils.getValue(item.path, doc), item);
} else {
this.populated(item.path, item._docs[id], item);
}
}
}
init(this, doc, this._doc);
this.$__storeShard();
this.emit('init', this);
this.constructor.emit('init', this);
if (fn) {
fn(null);
}
return this;
}...
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
// apply methods
for (var m in schema.methods) {
this[m] = schema.methods[m];
...inspect = function (options) {
var isPOJO = options &&
utils.getFunctionName(options.constructor) === 'Object';
var opts;
if (isPOJO) {
opts = options;
opts.minimize = false;
opts.retainKeyOrder = true;
}
return this.toObject(opts);
}...
* Helper for console.log
*
* @api public
* @method toString
*/
Document.prototype.toString = function() {
return inspect(this.inspect());
};
/**
* Returns true if the Document stores the same data as doc.
*
* Documents are considered equal when they have matching `_id`s, unless neither
* document has an `_id`, in which case this function falls back to using
...invalidate = function (path, err, val, kind) {
if (!this.$__.validationError) {
this.$__.validationError = new ValidationError(this);
}
if (this.$__.validationError.errors[path]) {
return;
}
if (!err || typeof err === 'string') {
err = new ValidatorError({
path: path,
message: err,
type: kind || 'user defined',
value: val
});
}
if (this.$__.validationError === err) {
return this.$__.validationError;
}
this.$__.validationError.errors[path] = err;
return this.$__.validationError;
}...
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
}
} else {
...isDirectModified = function (path) {
return (path in this.$__.activePaths.states.modify);
}...
// Else mongodb throws: "LEFT_SUBFIELD only supports Object"
if (parts.length <= 1) {
pathToMark = path;
} else {
for (i = 0; i < parts.length; ++i) {
subpath = parts.slice(0, i + 1).join('.');
if (this.isDirectModified(subpath) // earlier prefixes that are already
// marked as dirty have precedence
|| this.get(subpath) === null) {
pathToMark = subpath;
break;
}
}
...function isDirectSelected(path) {
if (this.$__.selected) {
if (path === '_id') {
return this.$__.selected._id !== 0;
}
var paths = Object.keys(this.$__.selected);
var i = paths.length;
var inclusive = null;
var cur;
if (i === 1 && paths[0] === '_id') {
// only _id was selected.
return this.$__.selected._id === 0;
}
while (i--) {
cur = paths[i];
if (cur === '_id') {
continue;
}
if (this.$__.selected[cur] && this.$__.selected[cur].$meta) {
continue;
}
inclusive = !!this.$__.selected[cur];
break;
}
if (inclusive === null) {
return true;
}
if (path in this.$__.selected) {
return inclusive;
}
return !inclusive;
}
return true;
}...
/**
* Checks if `path` was explicitly selected. If no projection, always returns
* true.
*
* ####Example
*
* Thing.findOne().select('nested.name').exec(function (err, doc) {
* doc.isDirectSelected('nested.name') // true
* doc.isDirectSelected('nested.otherName') // false
* doc.isDirectSelected('nested') // false
* })
*
* @param {String} path
* @return {Boolean}
* @api public
...isInit = function (path) {
return (path in this.$__.activePaths.states.init);
}n/a
isModified = function (paths) {
if (paths) {
if (!Array.isArray(paths)) {
paths = paths.split(' ');
}
var modified = this.modifiedPaths();
var directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
var isModifiedChild = paths.some(function(path) {
return !!~modified.indexOf(path);
});
return isModifiedChild || paths.some(function(path) {
return directModifiedPaths.some(function(mod) {
return mod === path || path.indexOf(mod + '.') === 0;
});
});
}
return this.$__.activePaths.some('modify');
}...
}));
}
} else {
doc[i] = obj[i];
}
}
// mark as hydrated
if (!self.isModified(path)) {
self.$__.activePaths.init(path);
}
}
}
}
/**
...function isSelected(path) {
if (this.$__.selected) {
if (path === '_id') {
return this.$__.selected._id !== 0;
}
var paths = Object.keys(this.$__.selected);
var i = paths.length;
var inclusive = null;
var cur;
if (i === 1 && paths[0] === '_id') {
// only _id was selected.
return this.$__.selected._id === 0;
}
while (i--) {
cur = paths[i];
if (cur === '_id') {
continue;
}
if (this.$__.selected[cur] && this.$__.selected[cur].$meta) {
continue;
}
inclusive = !!this.$__.selected[cur];
break;
}
if (inclusive === null) {
return true;
}
if (path in this.$__.selected) {
return inclusive;
}
i = paths.length;
var pathDot = path + '.';
while (i--) {
cur = paths[i];
if (cur === '_id') {
continue;
}
if (cur.indexOf(pathDot) === 0) {
return inclusive || cur !== pathDot;
}
if (pathDot.indexOf(cur + '.') === 0) {
return inclusive;
}
}
return !inclusive;
}
return true;
}...
i = keys[index];
path = prefix + i;
schema = self.schema.path(path);
// Should still work if not a model-level discriminator, but should not be
// necessary. This is *only* to catch the case where we queried using the
// base model and the discriminated model has a projection
if (self.schema.$isRootDiscriminator && !self.isSelected(path)) {
return;
}
if (!schema && utils.isObject(obj[i]) &&
(!obj[i].constructor || utils.getFunctionName(obj[i].constructor) === 'Object')) {
// assume nested object
if (!doc[i]) {
...listeners = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}...
doc[pair[0]].apply(doc, pair[1]);
}
}
}
Document.prototype.$__handleReject = function handleReject(err) {
// emit on the Model if listening
if (this.listeners('error').length) {
this.emit('error', err);
} else if (this.constructor.listeners && this.constructor.listeners('error').length) {
this.constructor.emit('error', err);
} else if (this.listeners && this.listeners('error').length) {
this.emit('error', err);
}
};
...markModified = function (path) {
this.$__.activePaths.modify(path);
}...
if (!merge) {
this.setValue(path, null);
cleanModifiedSubpaths(this, path);
}
if (Object.keys(val).length === 0) {
this.setValue(path, {});
this.markModified(path);
cleanModifiedSubpaths(this, path);
} else {
this.set(val, path, constructing);
}
return this;
}
this.invalidate(path, new MongooseError.CastError('Object', val, path));
...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('.'));
}, []).filter(function(chain) {
return (list.indexOf(chain) === -1);
}));
}, []);
}...
*/
Document.prototype.isModified = function(paths) {
if (paths) {
if (!Array.isArray(paths)) {
paths = paths.split(' ');
}
var modified = this.modifiedPaths();
var directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
var isModifiedChild = paths.some(function(path) {
return !!~modified.indexOf(path);
});
return isModifiedChild || paths.some(function(path) {
return directModifiedPaths.some(function(mod) {
return mod === path || path.indexOf(mod + '.') === 0;
...on = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}...
require('http').createServer(function(req, res) {
if (req.url === '/favicon.ico') {
req.destroy();
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
...once = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}...
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
return;
}
_this._model.collection.emitter.once('queue', function() {
var cursor = _this._model.collection.
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
});
...function populate() {
if (arguments.length === 0) {
return this;
}
var pop = this.$__.populate || (this.$__.populate = {});
var args = utils.args(arguments);
var fn;
if (typeof args[args.length - 1] === 'function') {
fn = args.pop();
}
// allow `doc.populate(callback)`
if (args.length) {
// use hash to remove duplicate paths
var res = utils.populate.apply(null, args);
for (var i = 0; i < res.length; ++i) {
pop[res[i].path] = res[i];
}
}
if (fn) {
var paths = utils.object.vals(pop);
this.$__.populate = undefined;
paths.__noPromise = true;
this.constructor.populate(this, paths, fn);
}
return this;
}...
* Populates document references, executing the `callback` when complete.
* If you want to use promises instead, use this function with
* [`execPopulate()`](#document_Document-execPopulate)
*
* ####Example:
*
* doc
* .populate('company')
* .populate({
* path: 'notes',
* match: /airline/,
* select: 'text',
* model: 'modelName'
* options: opts
* }, function (err, user) {
...populated = function (path, val, options) {
// val and options are internal
if (val === null || val === void 0) {
if (!this.$__.populated) {
return undefined;
}
var v = this.$__.populated[path];
if (v) {
return v.value;
}
return undefined;
}
// internal
if (val === true) {
if (!this.$__.populated) {
return undefined;
}
return this.$__.populated[path];
}
this.$__.populated || (this.$__.populated = {});
this.$__.populated[path] = {value: val, options: options};
return val;
}...
// If doc._id is not null or undefined
if (doc._id !== null && doc._id !== undefined &&
opts && opts.populated && opts.populated.length) {
var id = String(doc._id);
for (var i = 0; i < opts.populated.length; ++i) {
var item = opts.populated[i];
if (item.isVirtual) {
this.populated(item.path, utils.getValue(item.path, doc), item);
} else {
this.populated(item.path, item._docs[id], item);
}
}
}
init(this, doc, this._doc);
...removeAllListeners = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}n/a
removeListener = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}...
}
if (!(value && value.isMongooseDocumentArray) &&
(!options || !options.skipDocumentArrayCast)) {
value = new MongooseDocumentArray(value, this.path, doc);
if (prev && prev._handlers) {
for (var key in prev._handlers) {
doc.removeListener(key, prev._handlers[key]);
}
}
} else if (value && value.isMongooseDocumentArray) {
// We need to create a new array, otherwise change tracking will
// update the old doc (gh-4449)
value = new MongooseDocumentArray(value, this.path, doc);
}
...removePost = function (name, fnToRemove) {
var proto = this.prototype || this
, posts = proto._posts || (proto._posts || {});
if (!posts[name]) return this;
if (arguments.length === 1) {
// Remove all post callbacks for hook `name`
posts[name].length = 0;
} else {
posts[name] = posts[name].filter( function (currFn) {
return currFn !== fnToRemove;
});
}
return this;
}n/a
removePre = function (name, fnToRemove) {
var proto = this.prototype || this
, pres = proto._pres || (proto._pres || {});
if (!pres[name]) return this;
if (arguments.length === 1) {
// Remove all pre callbacks for hook `name`
pres[name].length = 0;
} else {
pres[name] = pres[name].filter( function (currFn) {
return currFn !== fnToRemove;
});
}
return this;
}n/a
set = function (path, val, type, options) {
if (type && utils.getFunctionName(type.constructor) === 'Object') {
options = type;
type = undefined;
}
var merge = options && options.merge,
adhoc = type && type !== true,
constructing = type === true,
adhocs;
var strict = options && 'strict' in options
? options.strict
: this.$__.strictMode;
if (adhoc) {
adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {});
adhocs[path] = Schema.interpretAsType(path, type, this.schema.options);
}
if (typeof path !== 'string') {
// new Document({ key: val })
if (path === null || path === void 0) {
var _ = path;
path = val;
val = _;
} else {
var prefix = val
? val + '.'
: '';
if (path instanceof Document) {
if (path.$__isNested) {
path = path.toObject();
} else {
path = path._doc;
}
}
var keys = Object.keys(path);
var len = keys.length;
var i = 0;
var pathtype;
var key;
if (len === 0 && !this.schema.options.minimize) {
if (val) {
this.set(val, {});
}
return this;
}
if (this.schema.options.retainKeyOrder) {
while (i < len) {
_handleIndex.call(this, i++);
}
} else {
while (len--) {
_handleIndex.call(this, len);
}
}
return this;
}
}
function _handleIndex(i) {
key = keys[i];
var pathName = prefix + key;
pathtype = this.schema.pathType(pathName);
if (path[key] !== null
&& path[key] !== void 0
// need to know if plain object - no Buffer, ObjectId, ref, etc
&& utils.isObject(path[key])
&& (!path[key].constructor || utils.getFunctionName(path[key].constructor) === 'Object')
&& pathtype !== 'virtual'
&& pathtype !== 'real'
&& !(this.$__path(pathName) instanceof MixedSchema)
&& !(this.schema.paths[pathName] &&
this.schema.paths[pathName].options &&
this.schema.paths[pathName].options.ref)) {
this.set(path[key], prefix + key, constructing);
} else if (strict) {
// Don't overwrite defaults with undefined keys (gh-3981)
if (constructing && path[key] === void 0 &&
this.get(key) !== void 0) {
return;
}
if (pathtype === 'real' || pathtype === 'virtual') {
// Check for setting single embedded schema to document (gh-3535)
var p = path[key];
if (this.schema.paths[pathName] &&
this.schema.paths[pathName].$isSingleNested &&
path[key] instanceof Document) {
p = p.toObject({ virtuals: false, transform: false });
}
this.set(prefix + key, p, constructing);
} else if (pathtype === 'nested' && path[key] instanceof Document) {
this.set(prefix + key,
path[key].toObject({transform: false}), constructing);
} else if (strict === 'throw') {
if (pathtype === 'nested') {
throw new ObjectExpectedError(key, path[key]);
} else {
throw new StrictModeError(key);
}
}
} else if (path[key] !== void 0) {
this.set(prefix + key, path[key], constructing);
}
}
var pathType = this.schema.pathType(path);
if (pathType === 'nested' && val) {
if (utils.isObject(val) &&
(!val.constructor || utils.getFunctionName(val.constructor) === 'Object')) {
if (!merge) {
this.setValue(path, null);
cleanModifiedSubpaths(this, path);
}
if (Object.keys(val).length === 0) {
this.setValue(path, {});
this.markModified(path);
cleanModifiedSubpaths(this, path);
} else {
this.set(val, path, constructing);
}
return this;
}
this.invalidate(path, new MongooseError.CastError('Object', val, path));
return this;
}
var schema;
var parts = path.split('.');
if (pathType === 'adhocOrUndefined' && strict) {
// check for roots that are Mixed types ......
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
...setMaxListeners = function () {
return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
}...
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
...setValue = function (path, val) {
utils.setValue(path, val, this._doc);
return this;
}...
}
var pathType = this.schema.pathType(path);
if (pathType === 'nested' && val) {
if (utils.isObject(val) &&
(!val.constructor || utils.getFunctionName(val.constructor) === 'Object')) {
if (!merge) {
this.setValue(path, null);
cleanModifiedSubpaths(this, path);
}
if (Object.keys(val).length === 0) {
this.setValue(path, {});
this.markModified(path);
cleanModifiedSubpaths(this, path);
...toBSON = function () {
return this.toObject({
transform: false,
virtuals: false,
_skipDepopulateTopLevel: true,
depopulate: true,
flattenDecimals: false
});
}n/a
toJSON = function (options) {
return this.$toObject(options, true);
}...
if (Array.isArray(obj)) {
return cloneArray(obj, options);
}
if (isMongooseObject(obj)) {
if (options && options.json && typeof obj.toJSON === 'function') {
return obj.toJSON(options);
}
return obj.toObject(options);
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
...toObject = function (options) {
return this.$toObject(options);
}...
if (value.$maxDistance != null) {
value.$maxDistance = numbertype.castForQuery(value.$maxDistance);
}
if (value.$minDistance != null) {
value.$minDistance = numbertype.castForQuery(value.$minDistance);
}
if (utils.isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({
transform: false,
virtuals: false
});
}
value = value.$geometry.coordinates;
} else if (geo === '$geoWithin') {
if (value.$geometry) {
...toString = function () {
return inspect(this.inspect());
}...
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments.
To do so, just pass the new values to `next`:
```js
.pre(method, function firstPre (next, methodArg1, methodArg2) {
// Mutate methodArg1
next("altered-" + methodArg1.toString(), methodArg2);
});
// pre declaration is chainable
.pre(method, function secondPre (next, methodArg1, methodArg2) {
console.log(methodArg1);
// => 'altered-originalValOfMethodArg1'
...unmarkModified = function (path) {
this.$__.activePaths.init(path);
}...
/**
* Clears the modified state on the specified path.
*
* ####Example:
*
* doc.foo = 'bar';
* doc.unmarkModified('foo');
* doc.save() // changes to foo will not be persisted
*
* @param {String} path the path to unmark modified
* @api public
*/
Document.prototype.unmarkModified = function(path) {
...function update() {
var args = utils.args(arguments);
args.unshift({_id: this._id});
return this.constructor.update.apply(this.constructor, args);
}...
}
/**
* Sends an update command with this document `_id` as the query selector.
*
* ####Example:
*
* weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback);
*
* ####Valid options:
*
* - same as in [Model.update](#model_Model.update)
*
* @see Model.update #model_Model.update
* @param {Object} doc
...validate = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
this.$__validate(callback || function() {});
}...
*
* ####Note:
*
* This method is called `pre` save and if a validation rule is violated, [save](#model_Model-save) is aborted and the error is returned
to your `callback`.
*
* ####Example:
*
* doc.validate(function (err) {
* if (err) handleError(err);
* else // validation passed
* });
*
* @param {Object} optional options internal options
* @param {Function} callback optional callback called after validation completes, passing an error if one occurred
* @return {Promise} Promise
...validateSync = function (pathsToValidate) {
var _this = this;
if (typeof pathsToValidate === 'string') {
pathsToValidate = pathsToValidate.split(' ');
}
// only validate required fields when necessary
var paths = _getPathsToValidate(this);
if (pathsToValidate && pathsToValidate.length) {
var tmp = [];
for (var i = 0; i < paths.length; ++i) {
if (pathsToValidate.indexOf(paths[i]) !== -1) {
tmp.push(paths[i]);
}
}
paths = tmp;
}
var validating = {};
paths.forEach(function(path) {
if (validating[path]) {
return;
}
validating[path] = true;
var p = _this.schema.path(path);
if (!p) {
return;
}
if (!_this.$isValid(path)) {
return;
}
var val = _this.getValue(path);
var err = p.doValidateSync(val, _this);
if (err) {
_this.invalidate(path, err, undefined, true);
}
});
var err = _this.$__.validationError;
_this.$__.validationError = undefined;
_this.emit('validate', _this);
_this.constructor.emit('validate', _this);
if (err) {
for (var key in err.errors) {
// Make sure cast errors persist
if (err.errors[key] instanceof MongooseError.CastError) {
_this.invalidate(key, err.errors[key]);
}
}
}
return err;
}...
*
* ####Note:
*
* This method is useful if you need synchronous validation.
*
* ####Example:
*
* var err = doc.validateSync();
* if ( err ){
* handleError( err );
* } else {
* // validation passed
* }
*
* @param {Array|string} pathsToValidate only validate the given paths
...function DocumentArray(key, schema, options) {
var EmbeddedDocument = _createConstructor(schema, options);
ArrayType.call(this, key, EmbeddedDocument, options);
this.schema = schema;
this.$isMongooseDocumentArray = true;
var fn = this.defaultValue;
if (!('defaultValue' in this) || fn !== void 0) {
this.default(function() {
var arr = fn.call(this);
if (!Array.isArray(arr)) {
arr = [arr];
}
// Leave it up to `cast()` to convert this to a documentarray
return arr;
});
}
}n/a
cast = function (value, doc, init, prev, options) {
var selected,
subdoc,
i;
if (!Array.isArray(value)) {
// gh-2442 mark whole array as modified if we're initializing a doc from
// the db and the path isn't an array in the document
if (!!doc && init) {
doc.markModified(this.path);
}
return this.cast([value], doc, init, prev);
}
if (!(value && value.isMongooseDocumentArray) &&
(!options || !options.skipDocumentArrayCast)) {
value = new MongooseDocumentArray(value, this.path, doc);
if (prev && prev._handlers) {
for (var key in prev._handlers) {
doc.removeListener(key, prev._handlers[key]);
}
}
} else if (value && value.isMongooseDocumentArray) {
// We need to create a new array, otherwise change tracking will
// update the old doc (gh-4449)
value = new MongooseDocumentArray(value, this.path, doc);
}
i = value.length;
while (i--) {
if (!value[i]) {
continue;
}
var Constructor = this.casterConstructor;
if (Constructor.discriminators &&
typeof value[i][Constructor.schema.options.discriminatorKey] === 'string' &&
Constructor.discriminators[value[i][Constructor.schema.options.discriminatorKey]]) {
Constructor = Constructor.discriminators[value[i][Constructor.schema.options.discriminatorKey]];
}
// Check if the document has a different schema (re gh-3701)
if ((value[i] instanceof Subdocument) &&
value[i].schema !== Constructor.schema) {
value[i] = value[i].toObject({ transform: false, virtuals: false });
}
if (!(value[i] instanceof Subdocument) && value[i]) {
if (init) {
if (doc) {
selected || (selected = scopePaths(this, doc.$__.selected, init));
} else {
selected = true;
}
subdoc = new Constructor(null, value, true, selected, i);
value[i] = subdoc.init(value[i]);
} else {
if (prev && (subdoc = prev.id(value[i]._id))) {
subdoc = prev.id(value[i]._id);
}
if (prev && subdoc) {
// handle resetting doc with existing id but differing data
// doc.array = [{ doc: 'val' }]
subdoc.set(value[i]);
// if set() is hooked it will have no return value
// see gh-746
value[i] = subdoc;
} else {
try {
subdoc = new Constructor(value[i], value, undefined,
undefined, i);
// if set() is hooked it will have no return value
// see gh-746
value[i] = subdoc;
} catch (error) {
var valueInErrorMessage = util.inspect(value[i]);
throw new CastError('embedded', valueInErrorMessage,
value._path, error);
}
}
}
}
}
return value;
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...function DocumentArray(key, schema, options) {
var EmbeddedDocument = _createConstructor(schema, options);
ArrayType.call(this, key, EmbeddedDocument, options);
this.schema = schema;
this.$isMongooseDocumentArray = true;
var fn = this.defaultValue;
if (!('defaultValue' in this) || fn !== void 0) {
this.default(function() {
var arr = fn.call(this);
if (!Array.isArray(arr)) {
arr = [arr];
}
// Leave it up to `cast()` to convert this to a documentarray
return arr;
});
}
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...discriminator = function (name, schema) {
if (typeof name === 'function') {
name = utils.getFunctionName(name);
}
schema = discriminator(this.casterConstructor, name, schema);
var EmbeddedDocument = _createConstructor(schema);
EmbeddedDocument.baseCasterConstructor = this.casterConstructor;
try {
Object.defineProperty(EmbeddedDocument, 'name', {
value: name
});
} catch (error) {
// Ignore error, only happens on old versions of node
}
this.casterConstructor.discriminators[name] = EmbeddedDocument;
return this.casterConstructor.discriminators[name];
}...
* }
* util.inherits(BaseSchema, Schema);
*
* var PersonSchema = new BaseSchema();
* var BossSchema = new BaseSchema({ department: String });
*
* var Person = mongoose.model('Person', PersonSchema);
* var Boss = Person.discriminator('Boss', BossSchema);
*
* @param {String} name discriminator model name
* @param {Schema} schema discriminator model schema
* @api public
*/
Model.discriminator = function(name, schema) {
...doValidate = function (array, fn, scope, options) {
var _this = this;
SchemaType.prototype.doValidate.call(this, array, function(err) {
if (err) {
return fn(err);
}
var count = array && array.length;
var error;
if (!count) {
return fn();
}
if (options && options.updateValidator) {
return fn();
}
// handle sparse arrays, do not use array.forEach which does not
// iterate over sparse elements yet reports array.length including
// them :(
function callback(err) {
if (err) {
error = err;
}
--count || fn(error);
}
for (var i = 0, len = count; i < len; ++i) {
// sidestep sparse entries
var doc = array[i];
if (!doc) {
--count || fn(error);
continue;
}
// If you set the array index directly, the doc might not yet be
// a full fledged mongoose subdoc, so make it into one.
if (!(doc instanceof Subdocument)) {
doc = array[i] = new _this.casterConstructor(doc, array, undefined,
undefined, i);
}
// HACK: use $__original_validate to avoid promises so bluebird doesn't
// complain
if (doc.$__original_validate) {
doc.$__original_validate({__noPromise: true}, callback);
} else {
doc.validate({__noPromise: true}, callback);
}
}
}, scope);
}...
// If user marked as invalid or there was a cast error, don't validate
if (!_this.$isValid(path)) {
--total || complete();
return;
}
var val = _this.getValue(path);
p.doValidate(val, function(err) {
if (err) {
_this.invalidate(path, err, undefined, true);
}
--total || complete();
}, _this);
});
};
...doValidateSync = function (array, scope) {
var schemaTypeError = SchemaType.prototype.doValidateSync.call(this, array, scope);
if (schemaTypeError) {
return schemaTypeError;
}
var count = array && array.length,
resultError = null;
if (!count) {
return;
}
// handle sparse arrays, do not use array.forEach which does not
// iterate over sparse elements yet reports array.length including
// them :(
for (var i = 0, len = count; i < len; ++i) {
// only first error
if (resultError) {
break;
}
// sidestep sparse entries
var doc = array[i];
if (!doc) {
continue;
}
var subdocValidateError = doc.validateSync();
if (subdocValidateError) {
resultError = subdocValidateError;
}
}
return resultError;
}...
return;
}
if (!_this.$isValid(path)) {
return;
}
var val = _this.getValue(path);
var err = p.doValidateSync(val, _this);
if (err) {
_this.invalidate(path, err, undefined, true);
}
});
var err = _this.$__.validationError;
_this.$__.validationError = undefined;
...function Embedded(schema, path, options) {
var _embedded = function SingleNested(value, path, parent) {
var _this = this;
Subdocument.apply(this, arguments);
this.$parent = parent;
if (parent) {
parent.on('save', function() {
_this.emit('save', _this);
_this.constructor.emit('save', _this);
});
parent.on('isNew', function(val) {
_this.isNew = val;
_this.emit('isNew', val);
_this.constructor.emit('isNew', val);
});
}
};
_embedded.prototype = Object.create(Subdocument.prototype);
_embedded.prototype.$__setSchema(schema);
_embedded.prototype.constructor = _embedded;
_embedded.schema = schema;
_embedded.$isSingleNested = true;
_embedded.prototype.$basePath = path;
_embedded.prototype.toBSON = function() {
return this.toObject({
transform: false,
retainKeyOrder: schema.options.retainKeyOrder,
virtuals: false,
_skipDepopulateTopLevel: true,
depopulate: true,
flattenDecimals: false
});
};
// apply methods
for (var i in schema.methods) {
_embedded.prototype[i] = schema.methods[i];
}
// apply statics
for (i in schema.statics) {
_embedded[i] = schema.statics[i];
}
for (i in EventEmitter.prototype) {
_embedded[i] = EventEmitter.prototype[i];
}
applyHooks(_embedded, schema);
this.caster = _embedded;
this.schema = schema;
this.$isSingleNested = true;
SchemaType.call(this, path, options, 'Embedded');
}n/a
cast = function (val, doc, init) {
if (val && val.$isSingleNested) {
return val;
}
var subdoc = new this.caster(void 0, doc ? doc.$__.selected : void 0, doc);
if (init) {
subdoc.init(val);
} else {
subdoc.set(val, undefined, true);
}
return subdoc;
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional);
}
return handler.call(this, val);
}
val = $conditional;
if (val == null) {
return val;
}
return new this.caster(val);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...doValidate = function (value, fn, scope) {
var Constructor = this.caster;
SchemaType.prototype.doValidate.call(this, value, function(error) {
if (error) {
return fn(error);
}
if (!value) {
return fn(null);
}
if (!(value instanceof Constructor)) {
value = new Constructor(value);
}
value.validate(fn, {__noPromise: true});
}, scope);
}...
// If user marked as invalid or there was a cast error, don't validate
if (!_this.$isValid(path)) {
--total || complete();
return;
}
var val = _this.getValue(path);
p.doValidate(val, function(err) {
if (err) {
_this.invalidate(path, err, undefined, true);
}
--total || complete();
}, _this);
});
};
...doValidateSync = function (value, scope) {
var schemaTypeError = SchemaType.prototype.doValidateSync.call(this, value, scope);
if (schemaTypeError) {
return schemaTypeError;
}
if (!value) {
return;
}
return value.validateSync();
}...
return;
}
if (!_this.$isValid(path)) {
return;
}
var val = _this.getValue(path);
var err = p.doValidateSync(val, _this);
if (err) {
_this.invalidate(path, err, undefined, true);
}
});
var err = _this.$__.validationError;
_this.$__.validationError = undefined;
...function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
});
req.resume();
}).listen(8088);
...function CastError(type, value, path, reason) {
var stringValue = util.inspect(value);
stringValue = stringValue.replace(/^'/, '"').replace(/'$/, '"');
if (stringValue.charAt(0) !== '"') {
stringValue = '"' + stringValue + '"';
}
MongooseError.call(this, 'Cast to ' + type + ' failed for value ' +
stringValue + ' at path "' + path + '"');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.stringValue = stringValue;
this.name = 'CastError';
this.kind = type;
this.value = value;
this.path = path;
this.reason = reason;
}...
this.markModified(path);
cleanModifiedSubpaths(this, path);
} else {
this.set(val, path, constructing);
}
return this;
}
this.invalidate(path, new MongooseError.CastError('Object', val, path));
return this;
}
var schema;
var parts = path.split('.');
if (pathType === 'adhocOrUndefined' && strict) {
...function DivergentArrayError(paths) {
var msg = 'For your own good, using `document.save()` to update an array '
+ 'which was selected using an $elemMatch projection OR '
+ 'populated using skip, limit, query conditions, or exclusion of '
+ 'the _id field when the operation results in a $pop or $set of '
+ 'the entire array is not supported. The following '
+ 'path(s) would have been modified unsafely:\n'
+ ' ' + paths.join('\n ') + '\n'
+ 'Use Model.update() to update these arrays instead.';
// TODO write up a docs page (FAQ) and link to it
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'DivergentArrayError';
}n/a
function DocumentNotFoundError(query) {
MongooseError.call(this, 'No document found for query "' +
util.inspect(query) + '"');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'DocumentNotFoundError';
this.query = query;
}n/a
function MissingSchemaError(name) {
var msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
+ 'Use mongoose.model(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
}...
if (obj._id === undefined) {
obj._id = new ObjectId();
}
}
if (!schema) {
throw new MongooseError.MissingSchemaError();
}
this.$__setSchema(schema);
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
...function OverwriteModelError(name) {
MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'OverwriteModelError';
}...
throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
'schema or a POJO');
}
if (this.models[name] && !collection) {
// model exists but we are not subclassing with custom collection
if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
throw new MongooseError.OverwriteModelError(name);
}
return this.models[name];
}
var opts = {cache: false, connection: this};
var model;
...function ValidationError(instance) {
this.errors = {};
if (instance && instance.constructor.name === 'model') {
MongooseError.call(this, instance.constructor.modelName + ' validation failed');
} else {
MongooseError.call(this, 'Validation failed');
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ValidationError';
if (instance) {
instance.errors = this.errors;
}
}n/a
function ValidatorError(properties) {
var msg = properties.message;
if (!msg) {
msg = MongooseError.messages.general.default;
}
var message = this.formatMessage(msg, properties);
MongooseError.call(this, message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.properties = properties;
this.name = 'ValidatorError';
this.kind = properties.type;
this.path = properties.path;
this.value = properties.value;
this.reason = properties.reason;
}n/a
function VersionError(doc) {
MongooseError.call(this, 'No matching document found for id "' + doc._id +
'"');
this.name = 'VersionError';
}n/a
function Error() { [native code] }...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function MissingSchemaError(name) {
var msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
+ 'Use mongoose.model(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function Mixed(path, options) {
if (options && options.default) {
var def = options.default;
if (Array.isArray(def) && def.length === 0) {
// make sure empty array defaults are handled
options.default = Array;
} else if (!options.shared && utils.isObject(def) && Object.keys(def).length === 0) {
// prevent odd "shared" objects between documents
options.default = function() {
return {};
};
}
}
SchemaType.call(this, path, options, 'Mixed');
}n/a
cast = function (val) {
return val;
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($cond, val) {
if (arguments.length === 2) {
return val;
}
return $cond;
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...function Mixed(path, options) {
if (options && options.default) {
var def = options.default;
if (Array.isArray(def) && def.length === 0) {
// make sure empty array defaults are handled
options.default = Array;
} else if (!options.shared && utils.isObject(def) && Object.keys(def).length === 0) {
// prevent odd "shared" objects between documents
options.default = function() {
return {};
};
}
}
SchemaType.call(this, path, options, 'Mixed');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function Model(doc, fields, skipId) {
Document.call(this, doc, fields, skipId, true);
}...
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we
can access it through the same function
```js
var myModel = mongoose.model('ModelName');
```
Or just do it all at once
...function subclass(conn, schema, collection) {
// subclass model using this connection and collection name
var _this = this;
var Model = function Model(doc, fields, skipId) {
if (!(this instanceof Model)) {
return new Model(doc, fields, skipId);
}
_this.call(this, doc, fields, skipId);
};
Model.__proto__ = _this;
Model.prototype.__proto__ = _this.prototype;
Model.db = Model.prototype.db = conn;
var s = schema && typeof schema !== 'string'
? schema
: _this.prototype.schema;
var options = s.options || {};
if (!collection) {
collection = _this.prototype.schema.get('collection')
|| utils.toCollectionName(_this.modelName, options);
}
var collectionOptions = {
bufferCommands: s ? options.bufferCommands : true,
capped: s && options.capped
};
Model.prototype.collection = conn.collection(collection, collectionOptions);
Model.collection = Model.prototype.collection;
Model.init();
return Model;
}...
return model;
}
if (this.models[name] && collection) {
// subclassing current model with alternate collection
model = this.models[name];
schema = model.prototype.schema;
var sub = model.__subclass(this, schema, collection);
// do not cache the sub model
return sub;
}
// lookup model in mongoose module
model = this.base.models[name];
...function _getSchema(path) {
return this.schema._getSchema(path);
}...
modelNameFromQuery = options.model && options.model.modelName || options.model,
schema, refPath, Model, currentOptions, modelNames, modelName, discriminatorKey, modelForFindSchema;
var originalModel = options.model;
var isVirtual = false;
var isRefPathArray = false;
schema = model._getSchema(options.path);
var isUnderneathDocArray = schema && schema.$isUnderneathDocArray;
if (isUnderneathDocArray &&
options &&
options.options &&
options.options.sort) {
return new Error('Cannot populate with `sort` on path ' + options.path +
' because it is a subproperty of a document array');
...function addListener(type, listener) {
return _addListener(this, type, listener, false);
}n/a
function aggregate() {
var args = [].slice.call(arguments),
aggregate,
callback;
if (typeof args[args.length - 1] === 'function') {
callback = args.pop();
}
if (args.length === 1 && util.isArray(args[0])) {
aggregate = new Aggregate(args[0]);
} else {
aggregate = new Aggregate(args);
}
aggregate.model(this);
if (typeof callback === 'undefined') {
return aggregate;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
aggregate.exec(callback);
}...
* ####Example:
*
* new Aggregate();
* new Aggregate({ $project: { a: 1, b: 1 } });
* new Aggregate({ $project: { a: 1, b: 1 } }, { $skip: 5 });
* new Aggregate([{ $project: { a: 1, b: 1 } }, { $skip: 5 }]);
*
* Returned when calling Model.aggregate().
*
* ####Example:
*
* Model
* .aggregate({ $match: { age: { $gte: 21 }}})
* .unwind('tags')
* .exec(callback)
...bulkWrite = function (ops, options, callback) {
var Promise = PromiseProvider.get();
var _this = this;
if (typeof options === 'function') {
callback = options;
options = null;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
options = options || {};
var validations = ops.map(function(op) {
if (op['insertOne']) {
return function(callback) {
op['insertOne']['document'] = new _this(op['insertOne']['document']);
op['insertOne']['document'].validate({ __noPromise: true }, function(error) {
if (error) {
return callback(error);
}
callback(null);
});
};
} else if (op['updateOne']) {
return function(callback) {
try {
op['updateOne']['filter'] = cast(_this.schema,
op['updateOne']['filter']);
op['updateOne']['update'] = castUpdate(_this.schema,
op['updateOne']['update'], _this.schema.options.strict);
} catch (error) {
return callback(error);
}
callback(null);
};
} else if (op['updateMany']) {
return function(callback) {
try {
op['updateMany']['filter'] = cast(_this.schema,
op['updateMany']['filter']);
op['updateMany']['update'] = castUpdate(_this.schema, op['updateMany']['filter'], {
strict: _this.schema.options.strict,
overwrite: false
});
} catch (error) {
return callback(error);
}
callback(null);
};
} else if (op['replaceOne']) {
return function(callback) {
try {
op['replaceOne']['filter'] = cast(_this.schema,
op['replaceOne']['filter']);
} catch (error) {
return callback(error);
}
// set `skipId`, otherwise we get "_id field cannot be changed"
op['replaceOne']['replacement'] =
new _this(op['replaceOne']['replacement'], null, true);
op['replaceOne']['replacement'].validate({ __noPromise: true }, function(error) {
if (error) {
return callback(error);
}
callback(null);
});
};
} else if (op['deleteOne']) {
return function(callback) {
try {
op['deleteOne']['filter'] = cast(_this.schema,
op['deleteOne']['filter']);
} catch (error) {
return callback(error);
}
callback(null);
};
} else if (op['deleteMany']) {
return function(callback) {
try {
op['deleteMany']['filter'] = cast(_this.schema,
op['deleteMany']['filter']);
} catch (error) {
return callback(error);
}
callback(null);
};
} else {
return function(callback) {
callback(new Error('Invalid op passed to `bulkWrite()`'));
};
}
});
var promise = new Promise.ES6(function(resolve, reject) {
parallel(validations, function(error) {
if (error) {
callback && callback(error);
return reject(error);
}
_this.collection.bulkWrite(ops, options, function(error, res) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null, res);
resolve(res);
});
});
});
return promise;
}...
*
* Mongoose will perform casting on all operations you provide.
*
* This function does **not** trigger any middleware.
*
* ####Example:
*
* Character.bulkWrite([
* {
* insertOne: {
* document: {
* name: 'Eddard Stark',
* title: 'Warden of the North'
* }
* }
...function compile(name, schema, collectionName, connection, base) {
var versioningEnabled = schema.options.versionKey !== false;
if (versioningEnabled && !schema.paths[schema.options.versionKey]) {
// add versioning to top level documents only
var o = {};
o[schema.options.versionKey] = Number;
schema.add(o);
}
var model;
if (typeof name === 'function' && name.prototype instanceof Model) {
model = name;
name = model.name;
schema.loadClass(model, true);
model.prototype.$isMongooseModelPrototype = true;
} else {
// generate new class
model = function model(doc, fields, skipId) {
if (!(this instanceof model)) {
return new model(doc, fields, skipId);
}
Model.call(this, doc, fields, skipId);
};
}
model.hooks = schema.s.hooks.clone();
model.base = base;
model.modelName = name;
if (!(model.prototype instanceof Model)) {
model.__proto__ = Model;
model.prototype.__proto__ = Model.prototype;
}
model.model = Model.prototype.model;
model.db = model.prototype.db = connection;
model.discriminators = model.prototype.discriminators = undefined;
model.prototype.$__setSchema(schema);
var collectionOptions = {
bufferCommands: schema.options.bufferCommands,
capped: schema.options.capped
};
model.prototype.collection = connection.collection(
collectionName
, collectionOptions
);
// apply methods and statics
applyMethods(model, schema);
applyStatics(model, schema);
applyHooks(model, schema);
model.schema = model.prototype.schema;
model.collection = model.prototype.collection;
// Create custom query constructor
model.Query = function() {
Query.apply(this, arguments);
this.options.retainKeyOrder = model.schema.options.retainKeyOrder;
};
model.Query.prototype = Object.create(Query.prototype);
model.Query.base = Query.base;
applyQueryMethods(model, schema.query);
var kareemOptions = { useErrorHandlers: true };
model.$__insertMany = model.hooks.createWrapper('insertMany',
model.insertMany, model, kareemOptions);
model.insertMany = function(arr, options, callback) {
var Promise = PromiseProvider.get();
if (typeof options === 'function') {
callback = options;
options = null;
}
return new Promise.ES6(function(resolve, reject) {
model.$__insertMany(arr, options, function(error, result) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null, result);
resolve(result);
});
});
};
return model;
}...
callback && callback(err);
reject(err);
return;
}
if (ret.findOne && ret.mapReduce) {
// returned a collection, convert to Model
var model = Model.compile(
'_mapreduce_' + ret.collectionName
, Model.mapReduce.schema
, ret.collectionName
, _this.db
, _this.base);
model._mapreduce = true;
...function count(conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
// get the mongodb collection object
var mq = new this.Query({}, {}, this, this.collection);
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.count(conditions, callback);
}...
};
/**
* Counts number of matching documents in a database collection.
*
* ####Example:
*
* Adventure.count({ type: 'jungle' }, function (err, count) {
* if (err) ..
* console.log('there are %d jungle adventures', count);
* });
*
* @param {Object} conditions
* @param {Function} [callback]
* @return {Query}
...function create(doc, callback) {
var args;
var cb;
var discriminatorKey = this.schema.options.discriminatorKey;
if (Array.isArray(doc)) {
args = doc;
cb = callback;
} else {
var last = arguments[arguments.length - 1];
// Handle falsy callbacks re: #5061
if (typeof last === 'function' || !last) {
cb = last;
args = utils.args(arguments, 0, arguments.length - 1);
} else {
args = utils.args(arguments);
}
}
var Promise = PromiseProvider.get();
var _this = this;
if (cb) {
cb = this.$wrapCallback(cb);
}
var promise = new Promise.ES6(function(resolve, reject) {
if (args.length === 0) {
setImmediate(function() {
cb && cb(null);
resolve(null);
});
return;
}
var toExecute = [];
args.forEach(function(doc) {
toExecute.push(function(callback) {
var Model = _this.discriminators && doc[discriminatorKey] ?
_this.discriminators[doc[discriminatorKey]] :
_this;
var toSave = doc instanceof Model ? doc : new Model(doc);
var callbackWrapper = function(error, doc) {
if (error) {
return callback(error);
}
callback(null, doc);
};
// Hack to avoid getting a promise because of
// $__registerHooksFromSchema
if (toSave.$__original_save) {
toSave.$__original_save({ __noPromise: true }, callbackWrapper);
} else {
toSave.save({ __noPromise: true }, callbackWrapper);
}
});
});
parallel(toExecute, function(error, savedDocs) {
if (error) {
if (cb) {
cb(error);
} else {
reject(error);
}
return;
}
if (doc instanceof Array) {
resolve(savedDocs);
cb && cb.call(_this, null, savedDocs);
} else {
resolve.apply(promise, savedDocs);
if (cb) {
savedDocs.unshift(null);
cb.apply(_this, savedDocs);
}
}
});
});
return promise;
}...
}
}
/*!
* Inherit from the NodeJS document
*/
Document.prototype = Object.create(NodeJSDocument.prototype);
Document.prototype.constructor = Document;
/*!
* Browser doc exposes the event emitter API
*/
Document.$emitter = new EventEmitter();
...function deleteMany(conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
// get the mongodb collection object
var mq = new this.Query(conditions, {}, this, this.collection);
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.deleteMany(callback);
}...
/**
* Deletes the first document that matches `conditions` from the collection.
* Behaves like `remove()`, but deletes all documents that match `conditions`
* regardless of the `justOne` option.
*
* ####Example:
*
* Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }, function (err) {});
*
* ####Note:
*
* Like `Model.remove()`, this function does **not** trigger `pre('remove')` or `post('remove')` hooks.
*
* @param {Object} conditions
* @param {Function} [callback]
...function deleteOne(conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
// get the mongodb collection object
var mq = new this.Query(conditions, {}, this, this.collection);
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.deleteOne(callback);
}...
/**
* Deletes the first document that matches `conditions` from the collection.
* Behaves like `remove()`, but deletes at most one document regardless of the
* `justOne` option.
*
* ####Example:
*
* Character.deleteOne({ name: 'Eddard Stark' }, function (err) {});
*
* ####Note:
*
* Like `Model.remove()`, this function does **not** trigger `pre('remove')` or `post('remove')` hooks.
*
* @param {Object} conditions
* @param {Function} [callback]
...discriminator = function (name, schema) {
if (typeof name === 'function') {
name = utils.getFunctionName(name);
}
schema = discriminator(this, name, schema);
if (this.db.models[name]) {
throw new OverwriteModelError(name);
}
schema.$isRootDiscriminator = true;
this.discriminators[name] = this.db.model(name, schema, this.collection.name);
var d = this.discriminators[name];
d.prototype.__proto__ = this.prototype;
Object.defineProperty(d, 'baseModelName', {
value: this.modelName,
configurable: true,
writable: false
});
// apply methods and statics
applyMethods(d, schema);
applyStatics(d, schema);
return d;
}...
* }
* util.inherits(BaseSchema, Schema);
*
* var PersonSchema = new BaseSchema();
* var BossSchema = new BaseSchema({ department: String });
*
* var Person = mongoose.model('Person', PersonSchema);
* var Boss = Person.discriminator('Boss', BossSchema);
*
* @param {String} name discriminator model name
* @param {Schema} schema discriminator model schema
* @api public
*/
Model.discriminator = function(name, schema) {
...function distinct(field, conditions, callback) {
// get the mongodb collection object
var mq = new this.Query({}, {}, this, this.collection);
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.distinct(field, conditions, callback);
}...
/**
* Creates a Query for a `distinct` operation.
*
* Passing a `callback` immediately executes the query.
*
* ####Example
*
* Link.distinct('url', { clicks: {$gt: 100}}, function (err, result) {
* if (err) return handleError(err);
*
* assert(Array.isArray(result));
* console.log('unique urls with more than 100 clicks', result);
* })
*
* var query = Link.distinct('url');
...function emit(type) {
var er, handler, len, args, i, events, domain;
var needDomainExit = false;
var doError = (type === 'error');
events = this._events;
if (events)
doError = (doError && events.error == null);
else if (!doError)
return false;
domain = this.domain;
// If there is no 'error' event listener then throw.
if (doError) {
er = arguments[1];
if (domain) {
if (!er)
er = new Error('Uncaught, unspecified "error" event');
er.domainEmitter = this;
er.domain = domain;
er.domainThrown = false;
domain.emit('error', er);
} else if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
return false;
}
handler = events[type];
if (!handler)
return false;
if (domain && this !== process) {
domain.enter();
needDomainExit = true;
}
var isFn = typeof handler === 'function';
len = arguments.length;
switch (len) {
// fast cases
case 1:
emitNone(handler, isFn, this);
break;
case 2:
emitOne(handler, isFn, this, arguments[1]);
break;
case 3:
emitTwo(handler, isFn, this, arguments[1], arguments[2]);
break;
case 4:
emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
break;
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
emitMany(handler, isFn, this, args);
}
if (needDomainExit)
domain.exit();
return true;
}...
You can intercept method arguments via middleware.
For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to
a new value:
```js
schema.pre('set', function (next, path, val, typel) {
// `this` is the current Document
this.emit('set', path, val);
// Pass control to the next pre
next();
});
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments.
To do so, just pass the new values to `next`:
...function ensureIndexes(options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
if (options && options.__noPromise) {
_ensureIndexes(this, options, callback);
return;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
_ensureIndexes(_this, options || {}, function(error) {
if (error) {
callback && callback(error);
reject(error);
}
callback && callback();
resolve();
});
});
}...
*
* @api private
*/
Model.init = function init() {
if ((this.schema.options.autoIndex) ||
(this.schema.options.autoIndex === null && this.db.config.autoIndex)) {
this.ensureIndexes({ __noPromise: true, _automatic: true });
}
this.schema.emit('init', this);
};
/**
* Sends `ensureIndex` commands to mongo for each index declared in the schema.
...function eventNames() {
return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
}n/a
function find(conditions, projection, options, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
projection = null;
options = null;
} else if (typeof projection === 'function') {
callback = projection;
projection = null;
options = null;
} else if (typeof options === 'function') {
callback = options;
options = null;
}
var mq = new this.Query({}, {}, this, this.collection);
mq.select(projection);
mq.setOptions(options);
if (this.schema.discriminatorMapping && mq.selectedInclusively()) {
mq.select(this.schema.options.discriminatorKey);
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.find(conditions, callback);
}...
//
});
```
Or we can find documents from the same collection
```js
MyModel.find({}, function (err, docs) {
// docs.forEach
});
```
You can also `findOne`, `findById`, `update`, etc. For more details check out [the docs](http://mongoosejs.com/docs/queries.html
).
**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `
mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this
case access your model through the connection you created:
...function findById(id, projection, options, callback) {
if (typeof id === 'undefined') {
id = null;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return this.findOne({_id: id}, projection, options, callback);
}...
if (!err) console.log('Success!');
});
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
...findByIdAndRemove = function (id, options, callback) {
if (arguments.length === 1 && typeof id === 'function') {
var msg = 'Model.findByIdAndRemove(): First argument must not be a function.\n\n'
+ ' ' + this.modelName + '.findByIdAndRemove(id, callback)\n'
+ ' ' + this.modelName + '.findByIdAndRemove(id)\n'
+ ' ' + this.modelName + '.findByIdAndRemove()\n';
throw new TypeError(msg);
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return this.findOneAndRemove({_id: id}, options, callback);
}...
* - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* - `select`: sets the document fields to return
* - `passRawResult`: if true, passes the [raw result from the MongoDB driver as the third callback parameter](http://mongodb.github
.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
* - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
*
* ####Examples:
*
* A.findByIdAndRemove(id, options, callback) // executes
* A.findByIdAndRemove(id, options) // return Query
* A.findByIdAndRemove(id, callback) // executes
* A.findByIdAndRemove(id) // returns Query
* A.findByIdAndRemove() // returns Query
*
* @param {Object|Number|String} id value of `_id` to query by
* @param {Object} [options]
...findByIdAndUpdate = function (id, update, options, callback) {
if (callback) {
callback = this.$wrapCallback(callback);
}
if (arguments.length === 1) {
if (typeof id === 'function') {
var msg = 'Model.findByIdAndUpdate(): First argument must not be a function.\n\n'
+ ' ' + this.modelName + '.findByIdAndUpdate(id, callback)\n'
+ ' ' + this.modelName + '.findByIdAndUpdate(id)\n'
+ ' ' + this.modelName + '.findByIdAndUpdate()\n';
throw new TypeError(msg);
}
return this.findOneAndUpdate({_id: id}, undefined);
}
// if a model is passed in instead of an id
if (id instanceof Document) {
id = id._id;
}
return this.findOneAndUpdate.call(this, {_id: id}, update, options, callback);
}...
* - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* - `select`: sets the document fields to return
* - `passRawResult`: if true, passes the [raw result from the MongoDB driver as the third callback parameter](http://mongodb.github
.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
* - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
*
* ####Examples:
*
* A.findByIdAndUpdate(id, update, options, callback) // executes
* A.findByIdAndUpdate(id, update, options) // returns Query
* A.findByIdAndUpdate(id, update, callback) // executes
* A.findByIdAndUpdate(id, update) // returns Query
* A.findByIdAndUpdate() // returns Query
*
* ####Note:
*
...function findOne(conditions, projection, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
} else if (typeof projection === 'function') {
callback = projection;
projection = null;
options = null;
} else if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
projection = null;
options = null;
}
// get the mongodb collection object
var mq = new this.Query({}, {}, this, this.collection);
mq.select(projection);
mq.setOptions(options);
if (this.schema.discriminatorMapping && mq.selectedInclusively()) {
mq.select(this.schema.options.discriminatorKey);
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.findOne(conditions, callback);
}...
};
/**
* Checks if `path` was selected in the source query which initialized this document.
*
* ####Example
*
* Thing.findOne().select('name').exec(function (err, doc) {
* doc.isSelected('name') // true
* doc.isSelected('age') // false
* })
*
* @param {String} path
* @return {Boolean}
* @api public
...findOneAndRemove = function (conditions, options, callback) {
if (arguments.length === 1 && typeof conditions === 'function') {
var msg = 'Model.findOneAndRemove(): First argument must not be a function.\n\n'
+ ' ' + this.modelName + '.findOneAndRemove(conditions, callback)\n'
+ ' ' + this.modelName + '.findOneAndRemove(conditions)\n'
+ ' ' + this.modelName + '.findOneAndRemove()\n';
throw new TypeError(msg);
}
if (typeof options === 'function') {
callback = options;
options = undefined;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
var fields;
if (options) {
fields = options.select;
options.select = undefined;
}
var mq = new this.Query({}, {}, this, this.collection);
mq.select(fields);
return mq.findOneAndRemove(conditions, options, callback);
}...
* - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* - `select`: sets the document fields to return
* - `passRawResult`: if true, passes the [raw result from the MongoDB driver as the third callback parameter](http://mongodb.github
.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
* - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
*
* ####Examples:
*
* A.findOneAndRemove(conditions, options, callback) // executes
* A.findOneAndRemove(conditions, options) // return Query
* A.findOneAndRemove(conditions, callback) // executes
* A.findOneAndRemove(conditions) // returns Query
* A.findOneAndRemove() // returns Query
*
* Values are cast to their appropriate types when using the findAndModify helpers.
* However, the below are never executed.
...findOneAndUpdate = function (conditions, update, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
} else if (arguments.length === 1) {
if (typeof conditions === 'function') {
var msg = 'Model.findOneAndUpdate(): First argument must not be a function.\n\n'
+ ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options, callback)\n'
+ ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options)\n'
+ ' ' + this.modelName + '.findOneAndUpdate(conditions, update)\n'
+ ' ' + this.modelName + '.findOneAndUpdate(update)\n'
+ ' ' + this.modelName + '.findOneAndUpdate()\n';
throw new TypeError(msg);
}
update = conditions;
conditions = undefined;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
var fields;
if (options && options.fields) {
fields = options.fields;
}
update = utils.clone(update, {depopulate: 1, _isNested: true});
if (this.schema.options.versionKey && options && options.upsert) {
if (!update.$setOnInsert) {
update.$setOnInsert = {};
}
update.$setOnInsert[this.schema.options.versionKey] = 0;
}
var mq = new this.Query({}, {}, this, this.collection);
mq.select(fields);
return mq.findOneAndUpdate(conditions, update, options, callback);
}...
*
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if
any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned.
*
* ####Options:
*
* - `new`: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)
* - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
* - `fields`: {Object|String} - Field selection. Equivalent to `.select(fields).findOneAndUpdate
()`
* - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators
validate the update operation against the model's schema.
* - `setDefaultsOnInsert`: if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults
.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because
it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
* - `passRawResult`: if true, passes the [raw result from the MongoDB driver as the third callback parameter](http://mongodb.github
.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
* - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
*
...geoNear = function (near, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (callback) {
callback = this.$wrapCallback(callback);
}
var _this = this;
var Promise = PromiseProvider.get();
if (!near) {
return new Promise.ES6(function(resolve, reject) {
var error = new Error('Must pass a near option to geoNear');
reject(error);
callback && callback(error);
});
}
var x, y;
return new Promise.ES6(function(resolve, reject) {
var handler = function(err, res) {
if (err) {
reject(err);
callback && callback(err);
return;
}
if (options.lean) {
resolve(res.results, res.stats);
callback && callback(null, res.results, res.stats);
return;
}
var count = res.results.length;
// if there are no results, fulfill the promise now
if (count === 0) {
resolve(res.results, res.stats);
callback && callback(null, res.results, res.stats);
return;
}
var errSeen = false;
function init(err) {
if (err && !errSeen) {
errSeen = true;
reject(err);
callback && callback(err);
return;
}
if (--count <= 0) {
resolve(res.results, res.stats);
callback && callback(null, res.results, res.stats);
}
}
for (var i = 0; i < res.results.length; i++) {
var temp = res.results[i].obj;
res.results[i].obj = new _this();
res.results[i].obj.init(temp, init);
}
};
if (Array.isArray(near)) {
if (near.length !== 2) {
var error = new Error('If using legacy coordinates, must be an array ' +
'of size 2 for geoNear');
reject(error);
callback && callback(error);
return;
}
x = near[0];
y = near[1];
_this.collection.geoNear(x, y, options, handler);
} else {
if (near.type !== 'Point' || !Array.isArray(near.coordinates)) {
error = new Error('Must pass either a legacy coordinate array or ' +
'GeoJSON Point to geoNear');
reject(error);
callback && callback(error);
return;
}
_this.collection.geoNear(near, options, handler);
}
});
}...
* ####Options:
* - `lean` {Boolean} return the raw object
* - All options supported by the driver are also supported
*
* ####Example:
*
* // Legacy point
* Model.geoNear([1,3], { maxDistance : 5, spherical : true }, function(err, results
, stats) {
* console.log(results);
* });
*
* // geoJson
* var point = { type : "Point", coordinates : [9,9] };
* Model.geoNear(point, { maxDistance : 5, spherical : true }, function(err, results, stats) {
* console.log(results);
...geoSearch = function (conditions, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (callback) {
callback = this.$wrapCallback(callback);
}
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
var error;
if (conditions === undefined || !utils.isObject(conditions)) {
error = new Error('Must pass conditions to geoSearch');
} else if (!options.near) {
error = new Error('Must specify the near option in geoSearch');
} else if (!Array.isArray(options.near)) {
error = new Error('near option must be an array [x, y]');
}
if (error) {
callback && callback(error);
reject(error);
return;
}
// send the conditions in the options object
options.search = conditions;
_this.collection.geoHaystackSearch(options.near[0], options.near[1], options, function(err, res) {
// have to deal with driver problem. Should be fixed in a soon-ish release
// (7/8/2013)
if (err) {
callback && callback(err);
reject(err);
return;
}
var count = res.results.length;
if (options.lean || count === 0) {
callback && callback(null, res.results, res.stats);
resolve(res.results, res.stats);
return;
}
var errSeen = false;
function init(err) {
if (err && !errSeen) {
callback && callback(err);
reject(err);
return;
}
if (!--count && !errSeen) {
callback && callback(null, res.results, res.stats);
resolve(res.results, res.stats);
}
}
for (var i = 0; i < res.results.length; i++) {
var temp = res.results[i];
res.results[i] = new _this();
res.results[i].init(temp, {}, init);
}
});
});
}...
/**
* Implements `$geoSearch` functionality for Mongoose
*
* ####Example:
*
* var options = { near: [10, 10], maxDistance: 5 };
* Locations.geoSearch({ type : "house" }, options, function(err, res) {
* console.log(res);
* });
*
* ####Options:
* - `near` {Array} x,y point to search for
* - `maxDistance` {Number} the maximum distance from the point near that a result can be
* - `limit` {Number} The maximum number of results to return
...function getMaxListeners() {
return $getMaxListeners(this);
}n/a
hydrate = function (obj) {
var model = require('./queryhelpers').createModel(this, obj);
model.init(obj);
return model;
}...
/**
* Shortcut for creating a new Document from existing raw data, pre-saved in the DB.
* The document returned has no paths marked as modified initially.
*
* ####Example:
*
* // hydrate previous data into a Mongoose document
* var mongooseCandy = Candy.hydrate({ _id: '54108337212ffb6d459f854c',
type: 'jelly bean' });
*
* @param {Object} obj
* @return {Document}
* @api public
*/
Model.hydrate = function(obj) {
...function init() {
if ((this.schema.options.autoIndex) ||
(this.schema.options.autoIndex === null && this.db.config.autoIndex)) {
this.ensureIndexes({ __noPromise: true, _automatic: true });
}
this.schema.emit('init', this);
}...
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
// apply methods
for (var m in schema.methods) {
this[m] = schema.methods[m];
...insertMany = function (arr, options, callback) {
var _this = this;
if (typeof options === 'function') {
callback = options;
options = null;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
if (!Array.isArray(arr)) {
arr = [arr];
}
var toExecute = [];
arr.forEach(function(doc) {
toExecute.push(function(callback) {
doc = new _this(doc);
doc.validate({ __noPromise: true }, function(error) {
if (error) {
// Option `ordered` signals that insert should be continued after reaching
// a failing insert. Therefore we delegate "null", meaning the validation
// failed. It's up to the next function to filter out all failed models
if (options != null && typeof options === 'object' && options['ordered'] === false) {
return callback(null, null);
}
return callback(error);
}
callback(null, doc);
});
});
});
parallel(toExecute, function(error, docs) {
if (error) {
callback && callback(error);
return;
}
// We filter all failed pre-validations by removing nulls
var docAttributes = docs.filter(function(doc) {
return doc != null;
});
// Quickly escape while there aren't any valid docAttributes
if (docAttributes.length < 1) {
callback && callback(null, []);
return;
}
var docObjects = docAttributes.map(function(doc) {
if (doc.schema.options.versionKey) {
doc[doc.schema.options.versionKey] = 0;
}
if (doc.initializeTimestamps) {
return doc.initializeTimestamps().toObject(POJO_TO_OBJECT_OPTIONS);
}
return doc.toObject(POJO_TO_OBJECT_OPTIONS);
});
_this.collection.insertMany(docObjects, options, function(error) {
if (error) {
callback && callback(error);
return;
}
for (var i = 0; i < docAttributes.length; ++i) {
docAttributes[i].isNew = false;
docAttributes[i].emit('isNew', false);
docAttributes[i].constructor.emit('isNew', false);
}
callback && callback(null, docAttributes);
});
});
}...
* document.
*
* This function does **not** trigger save middleware.
*
* ####Example:
*
* var arr = [{ name: 'Star Wars' }, { name: 'The Empire Strikes Back' }];
* Movies.insertMany(arr, function(error, docs) {});
*
* @param {Array|Object|*} doc(s)
* @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html
#insertMany)
* @param {Function} [callback] callback
* @return {Promise}
* @api public
*/
...function listenerCount(type) {
const events = this._events;
if (events) {
const evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener) {
return evlistener.length;
}
}
return 0;
}n/a
function listeners(type) {
var evlistener;
var ret;
var events = this._events;
if (!events)
ret = [];
else {
evlistener = events[type];
if (!evlistener)
ret = [];
else if (typeof evlistener === 'function')
ret = [evlistener];
else
ret = arrayClone(evlistener, evlistener.length);
}
return ret;
}...
doc[pair[0]].apply(doc, pair[1]);
}
}
}
Document.prototype.$__handleReject = function handleReject(err) {
// emit on the Model if listening
if (this.listeners('error').length) {
this.emit('error', err);
} else if (this.constructor.listeners && this.constructor.listeners('error').length) {
this.constructor.emit('error', err);
} else if (this.listeners && this.listeners('error').length) {
this.emit('error', err);
}
};
...function mapReduce(o, callback) {
var _this = this;
if (callback) {
callback = this.$wrapCallback(callback);
}
var resolveToObject = o.resolveToObject;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
if (!Model.mapReduce.schema) {
var opts = {noId: true, noVirtualId: true, strict: false};
Model.mapReduce.schema = new Schema({}, opts);
}
if (!o.out) o.out = {inline: 1};
if (o.verbose !== false) o.verbose = true;
o.map = String(o.map);
o.reduce = String(o.reduce);
if (o.query) {
var q = new _this.Query(o.query);
q.cast(_this);
o.query = q._conditions;
q = undefined;
}
_this.collection.mapReduce(null, null, o, function(err, ret, stats) {
if (err) {
callback && callback(err);
reject(err);
return;
}
if (ret.findOne && ret.mapReduce) {
// returned a collection, convert to Model
var model = Model.compile(
'_mapreduce_' + ret.collectionName
, Model.mapReduce.schema
, ret.collectionName
, _this.db
, _this.base);
model._mapreduce = true;
callback && callback(null, model, stats);
return resolveToObject ? resolve({
model: model,
stats: stats
}) : resolve(model, stats);
}
callback && callback(null, ret, stats);
if (resolveToObject) {
return resolve({ model: ret, stats: stats });
}
resolve(ret, stats);
});
});
}...
* `o` is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver
implementation. See [node-mongodb-native mapReduce() documentation](http://mongodb.github.io/node-mongodb-native/api-generated/
collection.html#mapreduce) for more detail about options.
*
* ####Example:
*
* var o = {};
* o.map = function () { emit(this.name, 1) }
* o.reduce = function (k, vals) { return vals.length }
* User.mapReduce(o, function (err, results) {
* console.log(results)
* })
*
* ####Other options:
*
* - `query` {Object} query filter object.
* - `sort` {Object} sort input objects using this key
...function addListener(type, listener) {
return _addListener(this, type, listener, false);
}...
require('http').createServer(function(req, res) {
if (req.url === '/favicon.ico') {
req.destroy();
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
...function once(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.on(type, _onceWrap(this, type, listener));
return this;
}...
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
return;
}
_this._model.collection.emitter.once('queue', function() {
var cursor = _this._model.collection.
aggregate(_this._pipeline, options || {});
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
});
...populate = function (docs, paths, callback) {
var _this = this;
if (callback) {
callback = this.$wrapCallback(callback);
}
// normalized paths
var noPromise = paths && !!paths.__noPromise;
paths = utils.populate(paths);
// data that should persist across subPopulate calls
var cache = {};
if (noPromise) {
_populate(this, docs, paths, cache, callback);
} else {
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
_populate(_this, docs, paths, cache, function(error, docs) {
if (error) {
callback && callback(error);
reject(error);
} else {
callback && callback(null, docs);
resolve(docs);
}
});
});
}
}...
* Populates document references, executing the `callback` when complete.
* If you want to use promises instead, use this function with
* [`execPopulate()`](#document_Document-execPopulate)
*
* ####Example:
*
* doc
* .populate('company')
* .populate({
* path: 'notes',
* match: /airline/,
* select: 'text',
* model: 'modelName'
* options: opts
* }, function (err, user) {
...function prependListener(type, listener) {
return _addListener(this, type, listener, true);
}n/a
function prependOnceListener(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.prependListener(type, _onceWrap(this, type, listener));
return this;
}n/a
function remove(conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
// get the mongodb collection object
var mq = new this.Query(conditions, {}, this, this.collection);
if (callback) {
callback = this.$wrapCallback(callback);
}
return mq.remove(callback);
}...
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```
...function removeAllListeners(type) {
var listeners, events;
events = this._events;
if (!events)
return this;
// not listening for removeListener, no need to emit
if (!events.removeListener) {
if (arguments.length === 0) {
this._events = new EventHandlers();
this._eventsCount = 0;
} else if (events[type]) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else
delete events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
var keys = Object.keys(events);
for (var i = 0, key; i < keys.length; ++i) {
key = keys[i];
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = new EventHandlers();
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
do {
this.removeListener(type, listeners[listeners.length - 1]);
} while (listeners[0]);
}
return this;
}n/a
function removeListener(type, listener) {
var list, events, position, i, originalListener;
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
events = this._events;
if (!events)
return this;
list = events[type];
if (!list)
return this;
if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
position = -1;
for (i = list.length; i-- > 0;) {
if (list[i] === listener || list[i].listener === listener) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list[0] = undefined;
if (--this._eventsCount === 0) {
this._events = new EventHandlers();
return this;
} else {
delete events[type];
}
} else {
spliceOne(list, position);
}
if (events.removeListener)
this.emit('removeListener', type, originalListener || listener);
}
return this;
}...
}
if (!(value && value.isMongooseDocumentArray) &&
(!options || !options.skipDocumentArrayCast)) {
value = new MongooseDocumentArray(value, this.path, doc);
if (prev && prev._handlers) {
for (var key in prev._handlers) {
doc.removeListener(key, prev._handlers[key]);
}
}
} else if (value && value.isMongooseDocumentArray) {
// We need to create a new array, otherwise change tracking will
// update the old doc (gh-4449)
value = new MongooseDocumentArray(value, this.path, doc);
}
...function replaceOne(conditions, doc, options, callback) {
return _update(this, 'replaceOne', conditions, doc, options, callback);
}...
}
Query.base.updateOne.call(this, castedQuery, castedDoc, options, callback);
return this;
};
/*!
* Internal thunk for .replaceOne()
*
* @param {Function} callback
* @see Model.replaceOne #model_Model.replaceOne
* @api private
*/
Query.prototype._replaceOne = function(callback) {
var schema = this.model.schema;
...function setMaxListeners(n) {
if (typeof n !== 'number' || n < 0 || isNaN(n))
throw new TypeError('"n" argument must be a positive number');
this._maxListeners = n;
return this;
}...
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
...function update(conditions, doc, options, callback) {
return _update(this, 'update', conditions, doc, options, callback);
}...
}
/**
* Sends an update command with this document `_id` as the query selector.
*
* ####Example:
*
* weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback);
*
* ####Valid options:
*
* - same as in [Model.update](#model_Model.update)
*
* @see Model.update #model_Model.update
* @param {Object} doc
...function updateMany(conditions, doc, options, callback) {
return _update(this, 'updateMany', conditions, doc, options, callback);
}...
}
Query.base.update.call(this, castedQuery, castedDoc, options, callback);
return this;
};
/*!
* Internal thunk for .updateMany()
*
* @param {Function} callback
* @see Model.update #model_Model.update
* @api private
*/
Query.prototype._updateMany = function(callback) {
var schema = this.model.schema;
...function updateOne(conditions, doc, options, callback) {
return _update(this, 'updateOne', conditions, doc, options, callback);
}...
}
Query.base.updateMany.call(this, castedQuery, castedDoc, options, callback);
return this;
};
/*!
* Internal thunk for .updateOne()
*
* @param {Function} callback
* @see Model.update #model_Model.update
* @api private
*/
Query.prototype._updateOne = function(callback) {
var schema = this.model.schema;
...function where(path, val) {
void val; // eslint
// get the mongodb collection object
var mq = new this.Query({}, {}, this, this.collection).find({});
return mq.where.apply(mq, arguments);
}...
*
* For example, instead of writing:
*
* User.find({age: {$gte: 21, $lte: 65}}, callback);
*
* we can instead write:
*
* User.where('age').gte(21).lte(65).exec(callback);
*
* Since the Query class also supports `where` you can continue chaining
*
* User
* .where('age').gte(21).lte(65)
* .where('name', /^b/i)
* ... etc
...function increment() {
this.$__.version = VERSION_ALL;
return this;
}...
// only increment the version if an array position changes.
// modifying elements of an array is ok if position does not change.
if (op === '$push' || op === '$pushAll' || op === '$addToSet') {
self.$__.version = VERSION_INC;
} else if (/^\$p/.test(op)) {
// potentially changing array positions
self.increment();
} else if (Array.isArray(val)) {
// $set an array
self.increment();
} else if (/\.\d+\.|\.\d+$/.test(data.path)) {
// now handling $set, $unset
// subpath of array
self.$__.version = VERSION_WHERE;
...function model(name) {
return this.db.model(name);
}...
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we
can access it through the same function
```js
var myModel = mongoose.model('ModelName');
```
Or just do it all at once
...function remove(options, fn) {
if (typeof options === 'function') {
fn = options;
options = undefined;
}
if (!options) {
options = {};
}
if (this.$__.removing) {
if (fn) {
this.$__.removing.then(
function(res) { fn(null, res); },
function(err) { fn(err); });
}
return this;
}
var _this = this;
var Promise = PromiseProvider.get();
if (fn) {
fn = this.constructor.$wrapCallback(fn);
}
this.$__.removing = new Promise.ES6(function(resolve, reject) {
var where = _this.$__where();
if (where instanceof Error) {
reject(where);
fn && fn(where);
return;
}
if (!options.safe && _this.schema.options.safe) {
options.safe = _this.schema.options.safe;
}
_this.collection.remove(where, options, function(err) {
if (!err) {
_this.emit('remove', _this);
_this.constructor.emit('remove', _this);
resolve(_this);
fn && fn(null, _this);
return;
}
reject(err);
fn && fn(err);
});
});
return this.$__.removing;
}...
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```
...save = function (options, fn) {
if (typeof options === 'function') {
fn = options;
options = undefined;
}
if (!options) {
options = {};
}
if (fn) {
fn = this.constructor.$wrapCallback(fn);
}
return this.$__save(options, fn);
}...
Then Mongoose will create the model for your __tickets__ collection, not your __ticket__ collection.
Once we have our model, we can then instantiate it, and save it:
```js
var instance = new MyModel();
instance.my.key = 'hello';
instance.save(function (err) {
//
});
```
Or we can find documents from the same collection
```js
...function DocumentNotFoundError(query) {
MongooseError.call(this, 'No document found for query "' +
util.inspect(query) + '"');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'DocumentNotFoundError';
this.query = query;
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function SchemaNumber(key, options) {
SchemaType.call(this, key, options, 'Number');
}n/a
cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (value === null || value === undefined) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (typeof value === 'number') {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('number', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
var val = value && typeof value._id !== 'undefined' ?
value._id : // documents
value;
if (!isNaN(val)) {
if (val === null) {
return val;
}
if (val === '') {
return null;
}
if (typeof val === 'string' || typeof val === 'boolean') {
val = Number(val);
}
if (val instanceof Number) {
return val;
}
if (typeof val === 'number') {
return val;
}
if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) {
return new Number(val);
}
}
throw new CastError('number', value, this.path);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with Number.');
}
return handler.call(this, val);
}
val = this.cast($conditional);
return val;
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...function checkRequired(value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return !!value;
}
return typeof value === 'number' || value instanceof Number;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function SchemaNumber(key, options) {
SchemaType.call(this, key, options, 'Number');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...max = function (value, message) {
if (this.maxValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.maxValidator;
}, this);
}
if (value !== null && value !== undefined) {
var msg = message || MongooseError.messages.Number.max;
msg = msg.replace(/{MAX}/, value);
this.validators.push({
validator: this.maxValidator = function(v) {
return v == null || v <= value;
},
message: msg,
type: 'max',
max: value
});
}
return this;
}n/a
min = function (value, message) {
if (this.minValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.minValidator;
}, this);
}
if (value !== null && value !== undefined) {
var msg = message || MongooseError.messages.Number.min;
msg = msg.replace(/{MIN}/, value);
this.validators.push({
validator: this.minValidator = function(v) {
return v == null || v >= value;
},
message: msg,
type: 'min',
min: value
});
}
return this;
}n/a
function ObjectExpectedError(path, val) {
MongooseError.call(this, 'Tried to set nested object field `' + path +
'` to primitive value `' + val + '` and strict mode is set to throw.');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ObjectExpectedError';
this.path = path;
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function ObjectId(key, options) {
SchemaType.call(this, key, options, 'ObjectID');
}n/a
auto = function (turnOn) {
if (turnOn) {
this.default(defaultId);
this.set(resetId);
}
return this;
}n/a
cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (value === null || value === undefined) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (value instanceof oid) {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('ObjectId', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = value;
if (!doc.$__.populated ||
!doc.$__.populated[path] ||
!doc.$__.populated[path].options ||
!doc.$__.populated[path].options.options ||
!doc.$__.populated[path].options.options.lean) {
ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
}
return ret;
}
if (value === null || value === undefined) {
return value;
}
if (value instanceof oid) {
return value;
}
if (value._id) {
if (value._id instanceof oid) {
return value._id;
}
if (value._id.toString instanceof Function) {
try {
return new oid(value._id.toString());
} catch (e) {
}
}
}
if (value.toString instanceof Function) {
try {
return new oid(value.toString());
} catch (err) {
throw new CastError('ObjectId', value, this.path);
}
}
throw new CastError('ObjectId', value, this.path);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with ObjectId.');
}
return handler.call(this, val);
}
return this.cast($conditional);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...function checkRequired(value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return !!value;
}
return value instanceof oid;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function ObjectId(key, options) {
SchemaType.call(this, key, options, 'ObjectID');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function OverwriteModelError(name) {
MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
Error.captureStackTrace && Error.captureStackTrace(this, arguments.callee);
this.name = 'OverwriteModelError';
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function Promise(fn) {
MPromise.call(this, fn);
}n/a
ES6 = function (resolver) {
var promise = new Promise();
// No try/catch for backwards compatibility
resolver(
function() {
promise.complete.apply(promise, arguments);
},
function(e) {
promise.error(e);
});
return promise;
}...
* @param {Function} callback
* @return {Promise}
*/
Aggregate.prototype.explain = function(callback) {
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
if (!_this._pipeline.length) {
var err = new Error('Aggregate has empty pipeline');
if (callback) {
callback(err);
}
reject(err);
return;
...addBack = function (fn) {
if (!fn) return this;
if ('function' != typeof fn) throw new TypeError("fn should be a function");
this.on(Promise.FAILURE, function (err) { fn.call(this, err); });
this.on(Promise.SUCCESS, function () { fn.apply(this, strongUnshift(null, arguments)); });
return this;
}...
* // executing a query explicitly
* var query = MyModel.find({ name: /john/i }, null, { skip: 10 })
* query.exec(function (err, docs) {});
*
* // using the promise returned from executing a query
* var query = MyModel.find({ name: /john/i }, null, { skip: 10 });
* var promise = query.exec();
* promise.addBack(function (err, docs) {});
*
* @param {Object} conditions
* @param {Object} [projection] optional fields to return (http://bit.ly/1HotzBo)
* @param {Object} [options] optional
* @param {Function} [callback]
* @return {Query}
* @see field selection #query_Query-select
...addCallback = function (fn) {
if (!fn) return this;
if ('function' != typeof fn) throw new TypeError("fn should be a function");
return this.on(Promise.SUCCESS, fn);
}n/a
addErrback = function (fn) {
if (!fn) return this;
if ('function' != typeof fn) throw new TypeError("fn should be a function");
return this.on(Promise.FAILURE, fn);
}n/a
catch = function (onReject) {
return this.then(null, onReject);
}...
Promise.prototype.then = util.deprecate(Promise.prototype.then,
'Mongoose: mpromise (mongoose\'s default promise library) is deprecated, ' +
'plug in your own promise library instead: ' +
'http://mongoosejs.com/docs/promises.html');
/**
* ES6-style `.catch()` shorthand
*
* @method catch
* @memberOf Promise
* @param {Function} onReject
* @return {Promise}
* @api public
*/
...complete = function () {
return this.safeEmit.apply(this, strongUnshift(Promise.SUCCESS, arguments));
}n/a
error = function (err) {
if (!(err instanceof Error)) {
if (err instanceof Object) {
err = util.inspect(err);
}
err = new Error(err);
}
return this.reject(err);
}...
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
});
req.resume();
}).listen(8088);
...resolve = function (err) {
if (err) return this.error(err);
return this.fulfill.apply(this, Array.prototype.slice.call(arguments, 1));
}n/a
function deprecated() {
warned = exports.printDeprecationMessage(msg, warned, deprecated);
if (new.target) {
return Reflect.construct(fn, arguments, new.target);
}
return fn.apply(this, arguments);
}...
*
* ####Example:
*
* aggregate.exec(callback);
*
* // Because a promise is returned, the `callback` is optional.
* var promise = aggregate.exec();
* promise.then(..);
*
* @see Promise #promise_Promise
* @param {Function} [callback]
* @return {Promise}
* @api public
*/
...function Promise(fn) {
MPromise.call(this, fn);
}n/a
get = function () {
return Promise._promise;
}...
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
...reset = function () {
Promise._promise = MPromise;
}...
* Set the current promise constructor
*
* @api private
*/
Promise.set = function(lib) {
if (lib === MPromise) {
return Promise.reset();
}
Promise._promise = require('./ES6Promise');
Promise._promise.use(lib);
require('mquery').Promise = Promise._promise.ES6;
};
/**
...set = function (lib) {
if (lib === MPromise) {
return Promise.reset();
}
Promise._promise = require('./ES6Promise');
Promise._promise.use(lib);
require('mquery').Promise = Promise._promise.ES6;
}...
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
...function Query(conditions, options, model, collection) {
// this stuff is for dealing with custom queries created by #toConstructor
if (!this._mongooseOptions) {
this._mongooseOptions = {};
}
// this is the case where we have a CustomQuery, we need to check if we got
// options passed in, and if we did, merge them in
if (options) {
var keys = Object.keys(options);
for (var i = 0; i < keys.length; ++i) {
var k = keys[i];
this._mongooseOptions[k] = options[k];
}
}
if (collection) {
this.mongooseCollection = collection;
}
if (model) {
this.model = model;
this.schema = model.schema;
}
// this is needed because map reduce returns a model that can be queried, but
// all of the queries on said model should be lean
if (this.model && this.model._mapreduce) {
this.lean();
}
// inherit mquery
mquery.call(this, this.mongooseCollection, options);
if (conditions) {
this.find(conditions);
}
if (this.schema) {
var kareemOptions = {
useErrorHandlers: true,
numCallbackParams: 1
};
this._count = this.model.hooks.createWrapper('count',
Query.prototype._count, this, kareemOptions);
this._execUpdate = this.model.hooks.createWrapper('update',
Query.prototype._execUpdate, this, kareemOptions);
this._find = this.model.hooks.createWrapper('find',
Query.prototype._find, this, kareemOptions);
this._findOne = this.model.hooks.createWrapper('findOne',
Query.prototype._findOne, this, kareemOptions);
this._findOneAndRemove = this.model.hooks.createWrapper('findOneAndRemove',
Query.prototype._findOneAndRemove, this, kareemOptions);
this._findOneAndUpdate = this.model.hooks.createWrapper('findOneAndUpdate',
Query.prototype._findOneAndUpdate, this, kareemOptions);
this._replaceOne = this.model.hooks.createWrapper('replaceOne',
Query.prototype._replaceOne, this, kareemOptions);
this._updateMany = this.model.hooks.createWrapper('updateMany',
Query.prototype._updateMany, this, kareemOptions);
this._updateOne = this.model.hooks.createWrapper('updateOne',
Query.prototype._updateOne, this, kareemOptions);
}
}n/a
function applyPaths() {
this._fields = this._fields || {};
helpers.applyPaths(this._fields, this.model.schema);
}...
*/
Query.prototype._find = function(callback) {
if (this._castError) {
callback(this._castError);
return this;
}
this._applyPaths();
this._fields = this._castFields(this._fields);
var fields = this._fieldsForExec();
var options = this._mongooseOptions;
var _this = this;
var cb = function(err, docs) {
...function _castFields(fields) {
var selected,
elemMatchKeys,
keys,
key,
out,
i;
if (fields) {
keys = Object.keys(fields);
elemMatchKeys = [];
i = keys.length;
// collect $elemMatch args
while (i--) {
key = keys[i];
if (fields[key].$elemMatch) {
selected || (selected = {});
selected[key] = fields[key];
elemMatchKeys.push(key);
}
}
}
if (selected) {
// they passed $elemMatch, cast em
try {
out = this.cast(this.model, selected);
} catch (err) {
return err;
}
// apply the casted field args
i = elemMatchKeys.length;
while (i--) {
key = elemMatchKeys[i];
fields[key] = out[key];
}
}
return fields;
}...
Query.prototype._find = function(callback) {
if (this._castError) {
callback(this._castError);
return this;
}
this._applyPaths();
this._fields = this._castFields(this._fields);
var fields = this._fieldsForExec();
var options = this._mongooseOptions;
var _this = this;
var cb = function(err, docs) {
if (err) {
...function _castUpdate(obj, overwrite) {
var strict;
if ('strict' in this._mongooseOptions) {
strict = this._mongooseOptions.strict;
} else if (this.schema && this.schema.options) {
strict = this.schema.options.strict;
} else {
strict = true;
}
return castUpdate(this.schema, obj, {
overwrite: overwrite,
strict: strict
});
}...
// validate the update part of the query
var castedDoc;
try {
var $options = {retainKeyOrder: true};
if (options && options.minimize) {
$options.minimize = true;
}
castedDoc = query._castUpdate(utils.clone(doc, $options),
(options && options.overwrite) || op === 'replaceOne');
} catch (err) {
query._castError = castedQuery;
if (callback) {
callback(err);
return query;
} else if (!options || !options.dontThrowCastError) {
..._count = function (callback) {
try {
this.cast(this.model);
} catch (err) {
process.nextTick(function() {
callback(err);
});
return this;
}
var conds = this._conditions;
var options = this._optionsForExec();
this._collection.count(conds, options, utils.tick(callback));
}...
}
this.op = 'count';
if (!callback) {
return this;
}
this._count(callback);
return this;
};
/**
* Declares or executes a distict() operation.
*
..._execUpdate = function (callback) {
var schema = this.model.schema;
var doValidate;
var _this;
var castedQuery = this._conditions;
var castedDoc = this._update;
var options = this.options;
if (this._castError) {
callback(this._castError);
return this;
}
if (this.options.runValidators) {
_this = this;
doValidate = updateValidators(this, schema, castedDoc, options);
var _callback = function(err) {
if (err) {
return callback(err);
}
Query.base.update.call(_this, castedQuery, castedDoc, options, callback);
};
try {
doValidate(_callback);
} catch (err) {
process.nextTick(function() {
callback(err);
});
}
return this;
}
Query.base.update.call(this, castedQuery, castedDoc, options, callback);
return this;
}...
if (!query._update) {
query._update = castedDoc;
}
// Hooks
if (callback) {
if (op === 'update') {
return query._execUpdate(callback);
}
return query['_' + op](callback);
}
return Query.base[op].call(query, castedQuery, castedDoc, options, callback);
}
..._find = function (callback) {
if (this._castError) {
callback(this._castError);
return this;
}
this._applyPaths();
this._fields = this._castFields(this._fields);
var fields = this._fieldsForExec();
var options = this._mongooseOptions;
var _this = this;
var cb = function(err, docs) {
if (err) {
return callback(err);
}
if (docs.length === 0) {
return callback(null, docs);
}
if (!options.populate) {
return options.lean === true
? callback(null, docs)
: completeMany(_this.model, docs, fields, null, callback);
}
var pop = helpers.preparePopulationOptionsMQ(_this, options);
pop.__noPromise = true;
_this.model.populate(docs, pop, function(err, docs) {
if (err) return callback(err);
return options.lean === true
? callback(null, docs)
: completeMany(_this.model, docs, fields, pop, callback);
});
};
return Query.base.find.call(this, {}, cb);
}...
}
// if we don't have a callback, then just return the query object
if (!callback) {
return Query.base.find.call(this);
}
this._find(callback);
return this;
};
/**
* Merges another Query or conditions object into this one.
*
..._findAndModify = function (type, callback) {
if (typeof callback !== 'function') {
throw new Error('Expected callback in _findAndModify');
}
var model = this.model;
var schema = model.schema;
var _this = this;
var castedQuery;
var castedDoc;
var fields;
var opts;
var doValidate;
castedQuery = castQuery(this);
if (castedQuery instanceof Error) {
return callback(castedQuery);
}
opts = this._optionsForExec(model);
if ('strict' in opts) {
this._mongooseOptions.strict = opts.strict;
}
if (type === 'remove') {
opts.remove = true;
} else {
if (!('new' in opts)) {
opts.new = false;
}
if (!('upsert' in opts)) {
opts.upsert = false;
}
if (opts.upsert || opts['new']) {
opts.remove = false;
}
castedDoc = castDoc(this, opts.overwrite);
castedDoc = setDefaultsOnInsert(this, schema, castedDoc, opts);
if (!castedDoc) {
if (opts.upsert) {
// still need to do the upsert to empty doc
var doc = utils.clone(castedQuery);
delete doc._id;
castedDoc = {$set: doc};
} else {
return this.findOne(callback);
}
} else if (castedDoc instanceof Error) {
return callback(castedDoc);
} else {
// In order to make MongoDB 2.6 happy (see
// https://jira.mongodb.org/browse/SERVER-12266 and related issues)
// if we have an actual update document but $set is empty, junk the $set.
if (castedDoc.$set && Object.keys(castedDoc.$set).length === 0) {
delete castedDoc.$set;
}
}
doValidate = updateValidators(this, schema, castedDoc, opts);
}
this._applyPaths();
var options = this._mongooseOptions;
if (this._fields) {
fields = utils.clone(this._fields);
opts.fields = this._castFields(fields);
if (opts.fields instanceof Error) {
return callback(opts.fields);
}
}
if (opts.sort) convertSortToArray(opts);
var cb = function(err, doc, res) {
if (err) {
return callback(err);
}
if (!doc || (utils.isObject(doc) && Object.keys(doc).length === 0)) {
if (opts.rawResult) {
return callback(null, res);
}
// opts.passRawResult will be deprecated soon
if (opts.passRawResult) {
return callback(null, null, decorateResult(res));
}
return callback(null, null);
}
if (!options.populate) {
if (options.lean === true) {
return _completeOneLean(doc, res, opts, callback);
}
return completeOne(_this.model, doc, res, opts, fields, null, callback);
}
var pop = helpers.preparePopulationOptionsMQ(_this, options);
pop.__noPromise = true;
_this.model.populate(doc, pop, function(err, doc) {
if (err) {
return callback(err);
}
if (options.lean === true) {
return _completeOneLean(doc, res, opts, callback);
}
return completeOne(_this.model, doc, res, opts, fields, pop, callback);
});
};
if (opts.runValidators && doValidate) {
var _callback = function(error) {
if (error) {
return callback(error);
}
_this._collection.findAndModify(castedQuery, castedDoc, opts, utils.tick(function(error, res) {
return cb(error, res ? res.value : res, res);
}));
};
try {
doValidate(_callback);
} catch (error) {
callback(error);
}
} else {
this._collection.findAndModify(castedQuery, castedDoc, opts, utils.tick(function(error, res) {
return cb(error, res ? res.value : res, res);
}));
}
return this;
}...
* Thunk around findOneAndUpdate()
*
* @param {Function} [callback]
* @api private
*/
Query.prototype._findOneAndUpdate = function(callback) {
this._findAndModify('update', callback);
return this;
};
/**
* Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command.
*
* Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback`
is passed.
..._findOne = function (callback) {
if (this._castError) {
return callback(this._castError);
}
this._applyPaths();
this._fields = this._castFields(this._fields);
var options = this._mongooseOptions;
var projection = this._fieldsForExec();
var _this = this;
// don't pass in the conditions because we already merged them in
Query.base.findOne.call(_this, {}, function(err, doc) {
if (err) {
return callback(err);
}
if (!doc) {
return callback(null, null);
}
if (!options.populate) {
return options.lean === true
? callback(null, doc)
: completeOne(_this.model, doc, null, {}, projection, null, callback);
}
var pop = helpers.preparePopulationOptionsMQ(_this, options);
pop.__noPromise = true;
_this.model.populate(doc, pop, function(err, doc) {
if (err) {
return callback(err);
}
return options.lean === true
? callback(null, doc)
: completeOne(_this.model, doc, null, {}, projection, pop, callback);
});
});
}...
}
if (!callback) {
// already merged in the conditions, don't need to send them in.
return Query.base.findOne.call(this);
}
this._findOne(callback);
return this;
};
/**
* Thunk around count()
*
..._findOneAndRemove = function (callback) {
Query.base.findOneAndRemove.call(this, callback);
}...
options && this.setOptions(options);
if (!callback) {
return this;
}
this._findOneAndRemove(callback);
return this;
};
/*!
* Thunk around findOneAndRemove()
*
..._findOneAndUpdate = function (callback) {
this._findAndModify('update', callback);
return this;
}...
this.setOptions(options);
}
if (!callback) {
return this;
}
return this._findOneAndUpdate(callback);
};
/*!
* Thunk around findOneAndUpdate()
*
* @param {Function} [callback]
* @api private
..._mergeUpdate = function (doc) {
if (!this._update) this._update = {};
if (doc instanceof Query) {
if (doc._update) {
utils.mergeClone(this._update, doc._update);
}
} else {
utils.mergeClone(this._update, doc);
}
}...
if (mquery.canMerge(criteria)) {
this.merge(criteria);
}
// apply doc
if (doc) {
this._mergeUpdate(doc);
}
if (options) {
options = utils.clone(options, { retainKeyOrder: true });
if (options.projection) {
this.select(options.projection);
delete options.projection;
..._optionsForExec = function (model) {
var options = Query.base._optionsForExec.call(this);
delete options.populate;
delete options.retainKeyOrder;
model = model || this.model;
if (!model) {
return options;
}
if (!('safe' in options) && model.schema.options.safe) {
options.safe = model.schema.options.safe;
}
if (!('readPreference' in options) && model.schema.options.read) {
options.readPreference = model.schema.options.read;
}
return options;
}...
process.nextTick(function() {
callback(err);
});
return this;
}
var conds = this._conditions;
var options = this._optionsForExec();
this._collection.count(conds, options, utils.tick(callback));
};
/**
* Specifying this query as a `count` query.
*
..._replaceOne = function (callback) {
var schema = this.model.schema;
var doValidate;
var _this;
var castedQuery = this._conditions;
var castedDoc = this._update;
var options = this.options;
if (this._castError) {
callback(this._castError);
return this;
}
if (this.options.runValidators) {
_this = this;
doValidate = updateValidators(this, schema, castedDoc, options);
var _callback = function(err) {
if (err) {
return callback(err);
}
Query.base.updateMany.call(_this, castedQuery, castedDoc, options, callback);
};
try {
doValidate(_callback);
} catch (err) {
process.nextTick(function() {
callback(err);
});
}
return this;
}
Query.base.replaceOne.call(this, castedQuery, castedDoc, options, callback);
return this;
}n/a
_updateForExec = function () {
var update = utils.clone(this._update, {
retainKeyOrder: true,
transform: false,
depopulate: true
});
var ops = Object.keys(update);
var i = ops.length;
var ret = {};
while (i--) {
var op = ops[i];
if (this.options.overwrite) {
ret[op] = update[op];
continue;
}
if ('$' !== op[0]) {
// fix up $set sugar
if (!ret.$set) {
if (update.$set) {
ret.$set = update.$set;
} else {
ret.$set = {};
}
}
ret.$set[op] = update[op];
ops.splice(i, 1);
if (!~ops.indexOf('$set')) ops.push('$set');
} else if ('$set' === op) {
if (!ret.$set) {
ret[op] = update[op];
}
} else {
ret[op] = update[op];
}
}
return ret;
}...
// if doc is undefined at this point, this means this function is being
// executed by exec(not always see below). Grab the update doc from here in
// order to validate
// This could also be somebody calling update() or update({}). Probably not a
// common use case, check for _update to make sure we don't do anything bad
if (!doc && query._update) {
doc = query._updateForExec();
}
if (mquery.canMerge(conditions)) {
query.merge(conditions);
}
// validate the selector part of the query
..._updateMany = function (callback) {
var schema = this.model.schema;
var doValidate;
var _this;
var castedQuery = this._conditions;
var castedDoc = this._update;
var options = this.options;
if (this._castError) {
callback(this._castError);
return this;
}
if (this.options.runValidators) {
_this = this;
doValidate = updateValidators(this, schema, castedDoc, options);
var _callback = function(err) {
if (err) {
return callback(err);
}
Query.base.updateMany.call(_this, castedQuery, castedDoc, options, callback);
};
try {
doValidate(_callback);
} catch (err) {
process.nextTick(function() {
callback(err);
});
}
return this;
}
Query.base.updateMany.call(this, castedQuery, castedDoc, options, callback);
return this;
}n/a
_updateOne = function (callback) {
var schema = this.model.schema;
var doValidate;
var _this;
var castedQuery = this._conditions;
var castedDoc = this._update;
var options = this.options;
if (this._castError) {
callback(this._castError);
return this;
}
if (this.options.runValidators) {
_this = this;
doValidate = updateValidators(this, schema, castedDoc, options);
var _callback = function(err) {
if (err) {
return callback(err);
}
Query.base.updateOne.call(_this, castedQuery, castedDoc, options, callback);
};
try {
doValidate(_callback);
} catch (err) {
process.nextTick(function() {
callback(err);
});
}
return this;
}
Query.base.updateOne.call(this, castedQuery, castedDoc, options, callback);
return this;
}n/a
box = function (ll, ur) {
if (!Array.isArray(ll) && utils.isObject(ll)) {
ur = ll.ur;
ll = ll.ll;
}
return Query.base.box.call(this, ll, ur);
}...
*/
/**
* Defines a `$within` or `$geoWithin` argument for geo-spatial queries.
*
* ####Example
*
* query.where(path).within().box()
* query.where(path).within().circle()
* query.where(path).within().geometry()
*
* query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
* query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
* query.where('loc').within({ polygon: [[],[],[],[]] });
*
...cast = function (model, obj) {
obj || (obj = this._conditions);
try {
return cast(model.schema, obj, {
upsert: this.options && this.options.upsert,
strict: (this.options && this.options.strict) ||
(model.schema.options && model.schema.options.strict)
});
} catch (err) {
// CastError, assign model
if (typeof err.setModel === 'function') {
err.setModel(model);
}
throw err;
}
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...catch = function (reject) {
return this.exec().then(null, reject);
}...
Promise.prototype.then = util.deprecate(Promise.prototype.then,
'Mongoose: mpromise (mongoose\'s default promise library) is deprecated, ' +
'plug in your own promise library instead: ' +
'http://mongoosejs.com/docs/promises.html');
/**
* ES6-style `.catch()` shorthand
*
* @method catch
* @memberOf Promise
* @param {Function} onReject
* @return {Promise}
* @api public
*/
...center = function () {
var path, val;
if (1 === arguments.length) {
this._ensurePath('circle');
path = this._path;
val = arguments[0];
} else if (2 === arguments.length) {
path = arguments[0];
val = arguments[1];
} else {
throw new TypeError("Invalid argument");
}
if (!('radius' in val && val.center))
throw new Error('center and radius are required');
var conds = this._conditions[path] || (this._conditions[path] = {});
var type = val.spherical
? '$centerSphere'
: '$center';
var wKey = this._geoComparison || $withinCmd;
conds[wKey] = {};
conds[wKey][type] = [val.center, val.radius];
if ('unique' in val)
conds[wKey].$uniqueDocs = !! val.unique;
return this;
}n/a
centerSphere = function () {
if (arguments[0] && arguments[0].constructor.name === 'Object') {
arguments[0].spherical = true;
}
if (arguments[1] && arguments[1].constructor.name === 'Object') {
arguments[1].spherical = true;
}
Query.base.circle.apply(this, arguments);
}...
* _DEPRECATED_ Specifies a $centerSphere condition
*
* **Deprecated.** Use [circle](#query_Query-circle) instead.
*
* ####Example
*
* var area = { center: [50, 50], radius: 10 };
* query.where('loc').within().centerSphere(area);
*
* @deprecated
* @param {String} [path]
* @param {Object} val
* @return {Query} this
* @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
* @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/
...collation = function (value) {
if (this.options == null) {
this.options = {};
}
this.options.collation = value;
return this;
}...
};
/**
* Adds a collation
*
* ####Example:
*
* Model.aggregate(..).collation({ locale: 'en_US', strength: 1 }).exec
();
*
* @param {Object} collation options
* @param {Boolean} value
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#aggregate
*/
Aggregate.prototype.collation = function(collation) {
...function Query(conditions, options, model, collection) {
// this stuff is for dealing with custom queries created by #toConstructor
if (!this._mongooseOptions) {
this._mongooseOptions = {};
}
// this is the case where we have a CustomQuery, we need to check if we got
// options passed in, and if we did, merge them in
if (options) {
var keys = Object.keys(options);
for (var i = 0; i < keys.length; ++i) {
var k = keys[i];
this._mongooseOptions[k] = options[k];
}
}
if (collection) {
this.mongooseCollection = collection;
}
if (model) {
this.model = model;
this.schema = model.schema;
}
// this is needed because map reduce returns a model that can be queried, but
// all of the queries on said model should be lean
if (this.model && this.model._mapreduce) {
this.lean();
}
// inherit mquery
mquery.call(this, this.mongooseCollection, options);
if (conditions) {
this.find(conditions);
}
if (this.schema) {
var kareemOptions = {
useErrorHandlers: true,
numCallbackParams: 1
};
this._count = this.model.hooks.createWrapper('count',
Query.prototype._count, this, kareemOptions);
this._execUpdate = this.model.hooks.createWrapper('update',
Query.prototype._execUpdate, this, kareemOptions);
this._find = this.model.hooks.createWrapper('find',
Query.prototype._find, this, kareemOptions);
this._findOne = this.model.hooks.createWrapper('findOne',
Query.prototype._findOne, this, kareemOptions);
this._findOneAndRemove = this.model.hooks.createWrapper('findOneAndRemove',
Query.prototype._findOneAndRemove, this, kareemOptions);
this._findOneAndUpdate = this.model.hooks.createWrapper('findOneAndUpdate',
Query.prototype._findOneAndUpdate, this, kareemOptions);
this._replaceOne = this.model.hooks.createWrapper('replaceOne',
Query.prototype._replaceOne, this, kareemOptions);
this._updateMany = this.model.hooks.createWrapper('updateMany',
Query.prototype._updateMany, this, kareemOptions);
this._updateOne = this.model.hooks.createWrapper('updateOne',
Query.prototype._updateOne, this, kareemOptions);
}
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...count = function (conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = undefined;
}
if (mquery.canMerge(conditions)) {
this.merge(conditions);
}
this.op = 'count';
if (!callback) {
return this;
}
this._count(callback);
return this;
}...
};
/**
* Counts number of matching documents in a database collection.
*
* ####Example:
*
* Adventure.count({ type: 'jungle' }, function (err, count) {
* if (err) ..
* console.log('there are %d jungle adventures', count);
* });
*
* @param {Object} conditions
* @param {Function} [callback]
* @return {Query}
...function cursor(opts) {
this._applyPaths();
this._fields = this._castFields(this._fields);
this.setOptions({ fields: this._fieldsForExec() });
if (opts) {
this.setOptions(opts);
}
try {
this.cast(this.model);
} catch (err) {
return (new QueryCursor(this, this.options))._markError(err);
}
return new QueryCursor(this, this.options);
}...
/**
* Sets the cursor option option for the aggregation query (ignored for < 2.6.0).
* Note the different syntax below: .exec() returns a cursor object, and no callback
* is necessary.
*
* ####Example:
*
* var cursor = Model.aggregate(..).cursor({ batchSize: 1000 }).exec();
* cursor.each(function(error, doc) {
* // use doc
* });
*
* @param {Object} options set the cursor batch size
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.0/api/AggregationCursor.html
*/
...deleteMany = function (cond, callback) {
if (typeof cond === 'function') {
callback = cond;
cond = null;
}
var cb = typeof callback === 'function';
try {
this.cast(this.model);
} catch (err) {
if (cb) return process.nextTick(callback.bind(null, err));
return this;
}
return Query.base.deleteMany.call(this, cond, callback);
}...
/**
* Deletes the first document that matches `conditions` from the collection.
* Behaves like `remove()`, but deletes all documents that match `conditions`
* regardless of the `justOne` option.
*
* ####Example:
*
* Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }, function (err) {});
*
* ####Note:
*
* Like `Model.remove()`, this function does **not** trigger `pre('remove')` or `post('remove')` hooks.
*
* @param {Object} conditions
* @param {Function} [callback]
...deleteOne = function (cond, callback) {
if (typeof cond === 'function') {
callback = cond;
cond = null;
}
var cb = typeof callback === 'function';
try {
this.cast(this.model);
} catch (err) {
if (cb) return process.nextTick(callback.bind(null, err));
return this;
}
return Query.base.deleteOne.call(this, cond, callback);
}...
/**
* Deletes the first document that matches `conditions` from the collection.
* Behaves like `remove()`, but deletes at most one document regardless of the
* `justOne` option.
*
* ####Example:
*
* Character.deleteOne({ name: 'Eddard Stark' }, function (err) {});
*
* ####Note:
*
* Like `Model.remove()`, this function does **not** trigger `pre('remove')` or `post('remove')` hooks.
*
* @param {Object} conditions
* @param {Function} [callback]
...distinct = function (field, conditions, callback) {
if (!callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = undefined;
} else if (typeof field === 'function') {
callback = field;
field = undefined;
conditions = undefined;
}
}
conditions = utils.toObject(conditions);
if (mquery.canMerge(conditions)) {
this.merge(conditions);
}
try {
this.cast(this.model);
} catch (err) {
if (!callback) {
throw err;
}
callback(err);
return this;
}
return Query.base.distinct.call(this, {}, field, callback);
}...
/**
* Creates a Query for a `distinct` operation.
*
* Passing a `callback` immediately executes the query.
*
* ####Example
*
* Link.distinct('url', { clicks: {$gt: 100}}, function (err, result) {
* if (err) return handleError(err);
*
* assert(Array.isArray(result));
* console.log('unique urls with more than 100 clicks', result);
* })
*
* var query = Link.distinct('url');
...function exec(op, callback) {
var Promise = PromiseProvider.get();
var _this = this;
if (typeof op === 'function') {
callback = op;
op = null;
} else if (typeof op === 'string') {
this.op = op;
}
var _results;
var promise = new Promise.ES6(function(resolve, reject) {
if (!_this.op) {
resolve();
return;
}
_this[_this.op].call(_this, function(error, res) {
if (error) {
reject(error);
return;
}
_results = arguments;
resolve(res);
});
});
if (callback) {
promise.then(
function() {
callback.apply(null, _results);
return null;
},
function(error) {
callback(error);
}).
catch(function(error) {
// If we made it here, we must have an error in the callback re:
// gh-4500, so we need to emit.
setImmediate(function() {
_this.model.emit('error', error);
});
});
}
return promise;
}...
function getVersion() {
var hist = fs.readFileSync('./History.md', 'utf8').replace(/\r/g, '\n').split('\n');
for (var i = 0; i < hist.length; ++i) {
var line = (hist[i] || '').trim();
if (!line) {
continue;
}
var match = /^\s*([^\s]+)\s/.exec(line);
if (match && match[1]) {
return match[1];
}
}
throw new Error('no match found');
}
...find = function (conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
conditions = utils.toObject(conditions);
if (mquery.canMerge(conditions)) {
this.merge(conditions);
}
prepareDiscriminatorCriteria(this);
try {
this.cast(this.model);
this._castError = null;
} catch (err) {
this._castError = err;
}
// if we don't have a callback, then just return the query object
if (!callback) {
return Query.base.find.call(this);
}
this._find(callback);
return this;
}...
//
});
```
Or we can find documents from the same collection
```js
MyModel.find({}, function (err, docs) {
// docs.forEach
});
```
You can also `findOne`, `findById`, `update`, etc. For more details check out [the docs](http://mongoosejs.com/docs/queries.html
).
**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `
mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this
case access your model through the connection you created:
...findOne = function (conditions, projection, options, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = null;
projection = null;
options = null;
} else if (typeof projection === 'function') {
callback = projection;
options = null;
projection = null;
} else if (typeof options === 'function') {
callback = options;
options = null;
}
// make sure we don't send in the whole Document to merge()
conditions = utils.toObject(conditions);
this.op = 'findOne';
if (options) {
this.setOptions(options);
}
if (projection) {
this.select(projection);
}
if (mquery.canMerge(conditions)) {
this.merge(conditions);
} else if (conditions != null) {
throw new Error('Invalid argument to findOne(): ' +
util.inspect(conditions));
}
prepareDiscriminatorCriteria(this);
try {
this.cast(this.model);
this._castError = null;
} catch (err) {
this._castError = err;
}
if (!callback) {
// already merged in the conditions, don't need to send them in.
return Query.base.findOne.call(this);
}
this._findOne(callback);
return this;
}...
};
/**
* Checks if `path` was selected in the source query which initialized this document.
*
* ####Example
*
* Thing.findOne().select('name').exec(function (err, doc) {
* doc.isSelected('name') // true
* doc.isSelected('age') // false
* })
*
* @param {String} path
* @return {Boolean}
* @api public
...findOneAndRemove = function (conditions, options, callback) {
this.op = 'findOneAndRemove';
this._validate();
switch (arguments.length) {
case 2:
if (typeof options === 'function') {
callback = options;
options = {};
}
break;
case 1:
if (typeof conditions === 'function') {
callback = conditions;
conditions = undefined;
options = undefined;
}
break;
}
if (mquery.canMerge(conditions)) {
this.merge(conditions);
}
options && this.setOptions(options);
if (!callback) {
return this;
}
this._findOneAndRemove(callback);
return this;
}...
* - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* - `select`: sets the document fields to return
* - `passRawResult`: if true, passes the [raw result from the MongoDB driver as the third callback parameter](http://mongodb.github
.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
* - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
*
* ####Examples:
*
* A.findOneAndRemove(conditions, options, callback) // executes
* A.findOneAndRemove(conditions, options) // return Query
* A.findOneAndRemove(conditions, callback) // executes
* A.findOneAndRemove(conditions) // returns Query
* A.findOneAndRemove() // returns Query
*
* Values are cast to their appropriate types when using the findAndModify helpers.
* However, the below are never executed.
...findOneAndUpdate = function (criteria, doc, options, callback) {
this.op = 'findOneAndUpdate';
this._validate();
switch (arguments.length) {
case 3:
if (typeof options === 'function') {
callback = options;
options = {};
}
break;
case 2:
if (typeof doc === 'function') {
callback = doc;
doc = criteria;
criteria = undefined;
}
options = undefined;
break;
case 1:
if (typeof criteria === 'function') {
callback = criteria;
criteria = options = doc = undefined;
} else {
doc = criteria;
criteria = options = undefined;
}
}
if (mquery.canMerge(criteria)) {
this.merge(criteria);
}
// apply doc
if (doc) {
this._mergeUpdate(doc);
}
if (options) {
options = utils.clone(options, { retainKeyOrder: true });
if (options.projection) {
this.select(options.projection);
delete options.projection;
}
if (options.fields) {
this.select(options.fields);
delete options.fields;
}
this.setOptions(options);
}
if (!callback) {
return this;
}
return this._findOneAndUpdate(callback);
}...
*
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if
any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned.
*
* ####Options:
*
* - `new`: bool - if true, return the modified document rather than the original. defaults to false (changed in 4.0)
* - `upsert`: bool - creates the object if it doesn't exist. defaults to false.
* - `fields`: {Object|String} - Field selection. Equivalent to `.select(fields).findOneAndUpdate
()`
* - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
* - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
* - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators
validate the update operation against the model's schema.
* - `setDefaultsOnInsert`: if this and `upsert` are true, mongoose will apply the [defaults](http://mongoosejs.com/docs/defaults
.html) specified in the model's schema if a new document is created. This option only works on MongoDB >= 2.4 because
it relies on [MongoDB's `$setOnInsert` operator](https://docs.mongodb.org/v2.4/reference/operator/update/setOnInsert/).
* - `passRawResult`: if true, passes the [raw result from the MongoDB driver as the third callback parameter](http://mongodb.github
.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
* - `strict`: overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict) for this update
*
...getQuery = function () {
return this._conditions;
}...
/**
* Returns the current query conditions as a JSON object.
*
* ####Example:
*
* var query = new Query();
* query.find({ a: 1 }).where('b').gt(2);
* query.getQuery(); // { a: 1, b: { $gt: 2 } }
*
* @return {Object} current query conditions
* @api public
*/
Query.prototype.getQuery = function() {
return this._conditions;
...getUpdate = function () {
return this._update;
}...
/**
* Returns the current update operations as a JSON object.
*
* ####Example:
*
* var query = new Query();
* query.update({}, { $set: { a: 5 } });
* query.getUpdate(); // { $set: { a: 5 } }
*
* @return {Object} current update operations
* @api public
*/
Query.prototype.getUpdate = function() {
return this._update;
...lean = function (v) {
this._mongooseOptions.lean = arguments.length ? !!v : true;
return this;
}...
* // include all properties except for `length`
* Adventure.findById(id, '-length').exec(function (err, adventure) {});
*
* // passing options (in this case return the raw js objects, not mongoose documents by passing `lean`
* Adventure.findById(id, 'name', { lean: true }, function (err, doc) {});
*
* // same as above
* Adventure.findById(id, 'name').lean().exec(function (err, doc) {});
*
* @param {Object|String|Number} id value of `_id` to query by
* @param {Object} [projection] optional fields to return (http://bit.ly/1HotzBo)
* @param {Object} [options] optional
* @param {Function} [callback]
* @return {Query}
* @see field selection #query_Query-select
...maxscan = function (v) {
this._validate(method);
this.options[method] = v;
return this;
}n/a
merge = function (source) {
if (!source) {
return this;
}
var opts = { retainKeyOrder: this.options.retainKeyOrder, overwrite: true };
if (source instanceof Query) {
// if source has a feature, apply it to ourselves
if (source._conditions) {
utils.merge(this._conditions, source._conditions, opts);
}
if (source._fields) {
this._fields || (this._fields = {});
utils.merge(this._fields, source._fields, opts);
}
if (source.options) {
this.options || (this.options = {});
utils.merge(this.options, source.options, opts);
}
if (source._update) {
this._update || (this._update = {});
utils.mergeClone(this._update, source._update);
}
if (source._distinct) {
this._distinct = source._distinct;
}
return this;
}
// plain object
utils.merge(this._conditions, source, opts);
return this;
}...
};
if (isVirtual && virtual.options && virtual.options.options) {
currentOptions.options = utils.clone(virtual.options.options, {
retainKeyOrder: true
});
}
utils.merge(currentOptions, options);
if (schema && !discriminatorKey) {
currentOptions.model = Model;
}
options.model = Model;
available[modelName] = {
Model: Model,
...mongooseOptions = function (v) {
if (arguments.length > 0) {
this._mongooseOptions = v;
}
return this._mongooseOptions;
}n/a
near = function () {
var params = [];
var sphere = this._mongooseOptions.nearSphere;
// TODO refactor
if (arguments.length === 1) {
if (Array.isArray(arguments[0])) {
params.push({center: arguments[0], spherical: sphere});
} else if (typeof arguments[0] === 'string') {
// just passing a path
params.push(arguments[0]);
} else if (utils.isObject(arguments[0])) {
if (typeof arguments[0].spherical !== 'boolean') {
arguments[0].spherical = sphere;
}
params.push(arguments[0]);
} else {
throw new TypeError('invalid argument');
}
} else if (arguments.length === 2) {
if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
params.push({center: [arguments[0], arguments[1]], spherical: sphere});
} else if (typeof arguments[0] === 'string' && Array.isArray(arguments[1])) {
params.push(arguments[0]);
params.push({center: arguments[1], spherical: sphere});
} else if (typeof arguments[0] === 'string' && utils.isObject(arguments[1])) {
params.push(arguments[0]);
if (typeof arguments[1].spherical !== 'boolean') {
arguments[1].spherical = sphere;
}
params.push(arguments[1]);
} else {
throw new TypeError('invalid argument');
}
} else if (arguments.length === 3) {
if (typeof arguments[0] === 'string' && typeof arguments[1] === 'number'
&& typeof arguments[2] === 'number') {
params.push(arguments[0]);
params.push({center: [arguments[1], arguments[2]], spherical: sphere});
} else {
throw new TypeError('invalid argument');
}
} else {
throw new TypeError('invalid argument');
}
return Query.base.near.apply(this, params);
}...
*
* ####NOTE:
*
* **MUST** be used as the first operator in the pipeline.
*
* ####Examples:
*
* aggregate.near({
* near: [40.724, -73.997],
* distanceField: "dist.calculated", // required
* maxDistance: 0.008,
* query: { type: "public" },
* includeLocs: "dist.location",
* uniqueDocs: true,
* num: 5
...nearSphere = function () {
this._mongooseOptions.nearSphere = true;
this.near.apply(this, arguments);
return this;
}...
};
/**
* _DEPRECATED_ Specifies a `$nearSphere` condition
*
* ####Example
*
* query.where('loc').nearSphere({ center: [10, 10], maxDistance: 5 });
*
* **Deprecated.** Use `query.near()` instead with the `spherical` option set to `true`.
*
* ####Example
*
* query.where('loc').near({ center: [10, 10], spherical: true });
*
...populate = function () {
if (arguments.length === 0) {
return this;
}
var res = utils.populate.apply(null, arguments);
var opts = this._mongooseOptions;
if (!utils.isObject(opts.populate)) {
opts.populate = {};
}
var pop = opts.populate;
for (var i = 0; i < res.length; ++i) {
var path = res[i].path;
if (pop[path] && pop[path].populate && res[i].populate) {
res[i].populate = pop[path].populate.concat(res[i].populate);
}
pop[res[i].path] = res[i];
}
return this;
}...
* Populates document references, executing the `callback` when complete.
* If you want to use promises instead, use this function with
* [`execPopulate()`](#document_Document-execPopulate)
*
* ####Example:
*
* doc
* .populate('company')
* .populate({
* path: 'notes',
* match: /airline/,
* select: 'text',
* model: 'modelName'
* options: opts
* }, function (err, user) {
...function read(pref, tags) {
// first cast into a ReadPreference object to support tags
var read = readPref.call(readPref, pref, tags);
return Query.base.read.call(this, read);
}...
};
/**
* Sets the readPreference option for the aggregation query.
*
* ####Example:
*
* Model.aggregate(..).read('primaryPreferred').exec(callback)
*
* @param {String} pref one of the listed preference options or their aliases
* @param {Array} [tags] optional tags for this query
* @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
* @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences
*/
...remove = function (cond, callback) {
if (typeof cond === 'function') {
callback = cond;
cond = null;
}
var cb = typeof callback === 'function';
try {
this.cast(this.model);
} catch (err) {
if (cb) return process.nextTick(callback.bind(null, err));
return this;
}
return Query.base.remove.call(this, cond, callback);
}...
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```
...replaceOne = function (conditions, doc, options, callback) {
if (typeof options === 'function') {
// .update(conditions, doc, callback)
callback = options;
options = null;
} else if (typeof doc === 'function') {
// .update(doc, callback);
callback = doc;
doc = conditions;
conditions = {};
options = null;
} else if (typeof conditions === 'function') {
// .update(callback)
callback = conditions;
conditions = undefined;
doc = undefined;
options = undefined;
} else if (typeof conditions === 'object' && !doc && !options && !callback) {
// .update(doc)
doc = conditions;
conditions = undefined;
options = undefined;
callback = undefined;
}
this.setOptions({ overwrite: true });
return _update(this, 'replaceOne', conditions, doc, options, callback);
}...
}
Query.base.updateOne.call(this, castedQuery, castedDoc, options, callback);
return this;
};
/*!
* Internal thunk for .replaceOne()
*
* @param {Function} callback
* @see Model.replaceOne #model_Model.replaceOne
* @api private
*/
Query.prototype._replaceOne = function(callback) {
var schema = this.model.schema;
...setOptions = function (options, overwrite) {
// overwrite is only for internal use
if (overwrite) {
// ensure that _mongooseOptions & options are two different objects
this._mongooseOptions = (options && utils.clone(options)) || {};
this.options = options || {};
if ('populate' in options) {
this.populate(this._mongooseOptions);
}
return this;
}
if (!(options && options.constructor.name === 'Object')) {
return this;
}
if (options && Array.isArray(options.populate)) {
var populate = options.populate;
delete options.populate;
var _numPopulate = populate.length;
for (var i = 0; i < _numPopulate; ++i) {
this.populate(populate[i]);
}
}
return Query.base.setOptions.call(this, options);
}...
} else if (typeof options === 'function') {
callback = options;
options = null;
}
var mq = new this.Query({}, {}, this, this.collection);
mq.select(projection);
mq.setOptions(options);
if (this.schema.discriminatorMapping && mq.selectedInclusively()) {
mq.select(this.schema.options.discriminatorKey);
}
if (callback) {
callback = this.$wrapCallback(callback);
}
...sort = function (arg) {
if (arguments.length > 1) {
throw new Error('sort() only takes 1 Argument');
}
return Query.base.sort.call(this, arg);
}...
* If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
*
* If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path
name is prefixed with `-` which will be treated as descending.
*
* ####Examples:
*
* // these are equivalent
* aggregate.sort({ field: 'asc', test: -1 });
* aggregate.sort('field -test');
*
* @see $sort http://docs.mongodb.org/manual/reference/aggregation/sort/
* @param {Object|String} arg
* @return {Aggregate} this
* @api public
*/
...function deprecated() {
warned = exports.printDeprecationMessage(msg, warned, deprecated);
if (new.target) {
return Reflect.construct(fn, arguments, new.target);
}
return fn.apply(this, arguments);
}...
/**
* Returns a Node.js 0.8 style [read stream](http://nodejs.org/docs/v0.8.21/api/stream.html#stream_readable_stream) interface.
*
* ####Example
*
* // follows the nodejs 0.8 stream api
* Thing.find({ name: /^hello/ }).stream().pipe(res)
*
* // manual streaming
* var stream = Thing.find({ name: /^hello/ }).stream();
*
* stream.on('data', function (doc) {
* // do something with the mongoose document
* }).on('error', function (err) {
...tailable = function (val, opts) {
// we need to support the tailable({ awaitdata : true }) as well as the
// tailable(true, {awaitdata :true}) syntax that mquery does not support
if (val && val.constructor.name === 'Object') {
opts = val;
val = true;
}
if (val === undefined) {
val = true;
}
if (opts && typeof opts === 'object') {
for (var key in opts) {
if (key === 'awaitdata') {
// For backwards compatibility
this.options[key] = !!opts[key];
} else {
this.options[key] = opts[key];
}
}
}
return Query.base.tailable.call(this, val);
}...
Query.prototype.maxscan = Query.base.maxScan;
/**
* Sets the tailable option (for use with capped collections).
*
* ####Example
*
* query.tailable() // true
* query.tailable(true)
* query.tailable(false)
*
* ####Note
*
* Cannot be used with `distinct()`
*
...then = function (resolve, reject) {
return this.exec().then(resolve, reject);
}...
*
* ####Example:
*
* aggregate.exec(callback);
*
* // Because a promise is returned, the `callback` is optional.
* var promise = aggregate.exec();
* promise.then(..);
*
* @see Promise #promise_Promise
* @param {Function} [callback]
* @return {Promise}
* @api public
*/
...function toConstructor() {
var model = this.model;
var coll = this.mongooseCollection;
var CustomQuery = function(criteria, options) {
if (!(this instanceof CustomQuery)) {
return new CustomQuery(criteria, options);
}
this._mongooseOptions = utils.clone(p._mongooseOptions);
Query.call(this, criteria, options || null, model, coll);
};
util.inherits(CustomQuery, Query);
// set inherited defaults
var p = CustomQuery.prototype;
p.options = {};
p.setOptions(this.options);
p.op = this.op;
p._conditions = utils.clone(this._conditions, { retainKeyOrder: true });
p._fields = utils.clone(this._fields);
p._update = utils.clone(this._update);
p._path = this._path;
p._distinct = this._distinct;
p._collection = this._collection;
p._mongooseOptions = this._mongooseOptions;
return CustomQuery;
}...
*
* // Create a query for adventure movies and read from the primary
* // node in the replica-set unless it is down, in which case we'll
* // read from a secondary node.
* var query = Movie.find({ tags: 'adventure' }).read('primaryPreferred');
*
* // create a custom Query constructor based off these settings
* var Adventure = query.toConstructor();
*
* // Adventure is now a subclass of mongoose.Query and works the same way but with the
* // default query parameters and options set.
* Adventure().exec(callback)
*
* // further narrow down our query results while still using the previous settings
* Adventure().where({ name: /^Life/ }).exec(callback);
...update = function (conditions, doc, options, callback) {
if (typeof options === 'function') {
// .update(conditions, doc, callback)
callback = options;
options = null;
} else if (typeof doc === 'function') {
// .update(doc, callback);
callback = doc;
doc = conditions;
conditions = {};
options = null;
} else if (typeof conditions === 'function') {
// .update(callback)
callback = conditions;
conditions = undefined;
doc = undefined;
options = undefined;
} else if (typeof conditions === 'object' && !doc && !options && !callback) {
// .update(doc)
doc = conditions;
conditions = undefined;
options = undefined;
callback = undefined;
}
return _update(this, 'update', conditions, doc, options, callback);
}...
}
/**
* Sends an update command with this document `_id` as the query selector.
*
* ####Example:
*
* weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback);
*
* ####Valid options:
*
* - same as in [Model.update](#model_Model.update)
*
* @see Model.update #model_Model.update
* @param {Object} doc
...updateMany = function (conditions, doc, options, callback) {
if (typeof options === 'function') {
// .update(conditions, doc, callback)
callback = options;
options = null;
} else if (typeof doc === 'function') {
// .update(doc, callback);
callback = doc;
doc = conditions;
conditions = {};
options = null;
} else if (typeof conditions === 'function') {
// .update(callback)
callback = conditions;
conditions = undefined;
doc = undefined;
options = undefined;
} else if (typeof conditions === 'object' && !doc && !options && !callback) {
// .update(doc)
doc = conditions;
conditions = undefined;
options = undefined;
callback = undefined;
}
return _update(this, 'updateMany', conditions, doc, options, callback);
}...
}
Query.base.update.call(this, castedQuery, castedDoc, options, callback);
return this;
};
/*!
* Internal thunk for .updateMany()
*
* @param {Function} callback
* @see Model.update #model_Model.update
* @api private
*/
Query.prototype._updateMany = function(callback) {
var schema = this.model.schema;
...updateOne = function (conditions, doc, options, callback) {
if (typeof options === 'function') {
// .update(conditions, doc, callback)
callback = options;
options = null;
} else if (typeof doc === 'function') {
// .update(doc, callback);
callback = doc;
doc = conditions;
conditions = {};
options = null;
} else if (typeof conditions === 'function') {
// .update(callback)
callback = conditions;
conditions = undefined;
doc = undefined;
options = undefined;
} else if (typeof conditions === 'object' && !doc && !options && !callback) {
// .update(doc)
doc = conditions;
conditions = undefined;
options = undefined;
callback = undefined;
}
return _update(this, 'updateOne', conditions, doc, options, callback);
}...
}
Query.base.updateMany.call(this, castedQuery, castedDoc, options, callback);
return this;
};
/*!
* Internal thunk for .updateOne()
*
* @param {Function} callback
* @see Model.update #model_Model.update
* @api private
*/
Query.prototype._updateOne = function(callback) {
var schema = this.model.schema;
...function QueryCursor(query, options) {
Readable.call(this, { objectMode: true });
this.cursor = null;
this.query = query;
this._transforms = options.transform ? [options.transform] : [];
var _this = this;
var model = query.model;
model.hooks.execPre('find', query, function() {
model.collection.find(query._conditions, options, function(err, cursor) {
if (_this._error) {
cursor.close(function() {});
_this.listeners('error').length > 0 && _this.emit('error', _this._error);
}
if (err) {
return _this.emit('error', err);
}
_this.cursor = cursor;
_this.emit('cursor', cursor);
});
});
}n/a
function Readable(options) {
if (!(this instanceof Readable))
return new Readable(options);
this._readableState = new ReadableState(options, this);
// legacy
this.readable = true;
if (options && typeof options.read === 'function')
this._read = options.read;
Stream.call(this);
}n/a
_markError = function (error) {
this._error = error;
return this;
}...
if (opts) {
this.setOptions(opts);
}
try {
this.cast(this.model);
} catch (err) {
return (new QueryCursor(this, this.options))._markError(err);
}
return new QueryCursor(this, this.options);
};
// the rest of these are basically to support older Mongoose syntax with mquery
..._read = function () {
var _this = this;
_next(this, function(error, doc) {
if (error) {
return _this.emit('error', error);
}
if (!doc) {
_this.push(null);
_this.cursor.close(function(error) {
if (error) {
return _this.emit('error', error);
}
setTimeout(function() {
_this.emit('close');
}, 0);
});
return;
}
_this.push(doc);
});
}n/a
close = function (callback) {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_this.cursor.close(function(error) {
if (error) {
callback && callback(error);
reject(error);
return _this.listeners('error').length > 0 &&
_this.emit('error', error);
}
_this.emit('close');
resolve();
callback && callback();
});
});
}...
* For practical reasons, a Connection equals a Db.
*
* @param {Mongoose} base a mongoose instance
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `connecting`: Emitted when `connection.{open,openSet}()` is executed on this connection.
* @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected
` scenarios.
* @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models.
* @event `disconnecting`: Emitted when `connection.close()` was executed.
* @event `disconnected`: Emitted after getting disconnected from the db.
* @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models.
* @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successfull
connection.
* @event `error`: Emitted when an error occurs on this connection.
* @event `fullsetup`: Emitted in a replica-set scenario, when primary and at least one seconaries specified in the connection string
are connected.
* @event `all`: Emitted in a replica-set scenario, when all nodes specified in the connection string are connected.
* @api public
...eachAsync = function (fn, callback) {
var Promise = PromiseProvider.get();
var _this = this;
var handleNextResult = function(doc, callback) {
var promise = fn(doc);
if (promise && typeof promise.then === 'function') {
promise.then(
function() { callback(null); },
function(error) { callback(error); });
} else {
callback(null);
}
};
var iterate = function(callback) {
return _next(_this, function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
return callback(null);
}
handleNextResult(doc, function(error) {
if (error) {
return callback(error);
}
// Make sure to clear the stack re: gh-4697
setTimeout(function() {
iterate(callback);
}, 0);
});
});
};
return new Promise.ES6(function(resolve, reject) {
iterate(function(error) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null);
return resolve();
});
});
}n/a
map = function (fn) {
this._transforms.push(fn);
return this;
}...
}
throw new Error('no match found');
}
function getUnstable(ver) {
ver = ver.replace('-pre');
var spl = ver.split('.');
spl = spl.map(function(i) {
return parseInt(i, 10);
});
spl[1]++;
spl[2] = 'x';
return spl.join('.');
}
...next = function (callback) {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_next(_this, function(error, doc) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null, doc);
resolve(doc);
});
});
}...
function(error) { callback(error); });
} else {
callback(null);
}
};
var iterate = function(callback) {
return cursor.next(function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
return callback(null);
}
handleNextResult(doc, function(error) {
...function applyPaths(fields, schema) {
// determine if query is selecting or excluding fields
var exclude;
var keys;
var ki;
if (fields) {
keys = Object.keys(fields);
ki = keys.length;
while (ki--) {
if (keys[ki][0] === '+') continue;
exclude = fields[keys[ki]] === 0;
break;
}
}
// if selecting, apply default schematype select:true fields
// if excluding, apply schematype select:false fields
var selected = [],
excluded = [],
seen = [];
var analyzePath = function(path, type) {
if (typeof type.selected !== 'boolean') return;
var plusPath = '+' + path;
if (fields && plusPath in fields) {
// forced inclusion
delete fields[plusPath];
// if there are other fields being included, add this one
// if no other included fields, leave this out (implied inclusion)
if (exclude === false && keys.length > 1 && !~keys.indexOf(path)) {
fields[path] = 1;
}
return;
}
// check for parent exclusions
var root = path.split('.')[0];
if (~excluded.indexOf(root)) return;
(type.selected ? selected : excluded).push(path);
};
var analyzeSchema = function(schema, prefix) {
prefix || (prefix = '');
// avoid recursion
if (~seen.indexOf(schema)) return;
seen.push(schema);
schema.eachPath(function(path, type) {
if (prefix) path = prefix + '.' + path;
analyzePath(path, type);
// array of subdocs?
if (type.schema) {
analyzeSchema(type.schema, path);
}
});
};
analyzeSchema(schema);
var i;
switch (exclude) {
case true:
for (i = 0; i < excluded.length; ++i) {
fields[excluded[i]] = 0;
}
break;
case false:
if (schema &&
schema.paths['_id'] &&
schema.paths['_id'].options &&
schema.paths['_id'].options.select === false) {
fields._id = 0;
}
for (i = 0; i < selected.length; ++i) {
fields[selected[i]] = 1;
}
break;
case undefined:
// user didn't specify fields, implies returning all fields.
// only need to apply excluded fields
for (i = 0; i < excluded.length; ++i) {
fields[excluded[i]] = 0;
}
break;
}
}...
var key = discriminatorMapping && discriminatorMapping.isRoot
? discriminatorMapping.key
: null;
if (key && doc[key] && model.discriminators && model.discriminators[doc[key]]) {
var discriminator = model.discriminators[doc[key]];
var _fields = utils.clone(fields);
exports.applyPaths(_fields, discriminator.schema);
return new model.discriminators[doc[key]](undefined, _fields, true);
}
return new model(undefined, fields, true);
};
/*!
...function createModel(model, doc, fields) {
var discriminatorMapping = model.schema
? model.schema.discriminatorMapping
: null;
var key = discriminatorMapping && discriminatorMapping.isRoot
? discriminatorMapping.key
: null;
if (key && doc[key] && model.discriminators && model.discriminators[doc[key]]) {
var discriminator = model.discriminators[doc[key]];
var _fields = utils.clone(fields);
exports.applyPaths(_fields, discriminator.schema);
return new model.discriminators[doc[key]](undefined, _fields, true);
}
return new model(undefined, fields, true);
}...
*
* @param {Object} obj
* @return {Document}
* @api public
*/
Model.hydrate = function(obj) {
var model = require('./queryhelpers').createModel(this, obj);
model.init(obj);
return model;
};
/**
* Updates one document in the database without returning it.
*
...function preparePopulationOptions(query, options) {
var pop = utils.object.vals(query.options.populate);
// lean options should trickle through all queries
if (options.lean) pop.forEach(makeLean);
return pop;
}n/a
function preparePopulationOptionsMQ(query, options) {
var pop = utils.object.vals(query._mongooseOptions.populate);
// lean options should trickle through all queries
if (options.lean) pop.forEach(makeLean);
return pop;
}...
var opts = ctx.query._mongooseOptions;
if (!opts.populate) {
return opts.lean === true ?
callback(null, doc) :
_create(ctx, doc, null, callback);
}
var pop = helpers.preparePopulationOptionsMQ(ctx.query,
ctx.query._mongooseOptions);
pop.forEach(function(option) {
delete option.model;
});
pop.__noPromise = true;
ctx.query.model.populate(doc, pop, function(err, doc) {
if (err) {
...function QueryStream(query, options) {
Stream.call(this);
this.query = query;
this.readable = true;
this.paused = false;
this._cursor = null;
this._destroyed = null;
this._fields = null;
this._buffer = null;
this._inline = T_INIT;
this._running = false;
this._transform = options && typeof options.transform === 'function'
? options.transform
: K;
// give time to hook up events
var _this = this;
process.nextTick(function() {
_this._init();
});
}n/a
__next = function () {
if (this.paused || this._destroyed) {
this._running = false;
return this._running;
}
var _this = this;
_this._inline = T_INIT;
_this._cursor.nextObject(function cursorcb(err, doc) {
_this._onNextObject(err, doc);
});
// if onNextObject() was already called in this tick
// return ourselves to the trampoline.
if (T_CONT === this._inline) {
return true;
}
// onNextObject() hasn't fired yet. tell onNextObject
// that its ok to call _next b/c we are not within
// the trampoline anymore.
this._inline = T_IDLE;
}...
while (!this.paused && !this._destroyed && (arg = this._buffer.shift())) { // eslint-disable-line no-cond
-assign
this._onNextObject.apply(this, arg);
}
}
// avoid stack overflows with large result sets.
// trampoline instead of recursion.
while (this.__next()) {
}
};
/**
* Pulls the next doc from the cursor.
*
* @see QueryStream#_next #querystream_QueryStream-_next
..._init = function () {
if (this._destroyed) {
return;
}
var query = this.query,
model = query.model,
options = query._optionsForExec(model),
_this = this;
try {
query.cast(model);
} catch (err) {
return _this.destroy(err);
}
_this._fields = utils.clone(query._fields);
options.fields = query._castFields(_this._fields);
model.collection.find(query._conditions, options, function(err, cursor) {
if (err) {
return _this.destroy(err);
}
_this._cursor = cursor;
_this._next();
});
}...
this._transform = options && typeof options.transform === 'function'
? options.transform
: K;
// give time to hook up events
var _this = this;
process.nextTick(function() {
_this._init();
});
}
/*!
* Inherit from Stream
*/
...function _next() {
if (this.paused || this._destroyed) {
this._running = false;
return this._running;
}
this._running = true;
if (this._buffer && this._buffer.length) {
var arg;
while (!this.paused && !this._destroyed && (arg = this._buffer.shift())) { // eslint-disable-line no-cond-assign
this._onNextObject.apply(this, arg);
}
}
// avoid stack overflows with large result sets.
// trampoline instead of recursion.
while (this.__next()) {
}
}...
options.fields = query._castFields(_this._fields);
model.collection.find(query._conditions, options, function(err, cursor) {
if (err) {
return _this.destroy(err);
}
_this._cursor = cursor;
_this._next();
});
};
/**
* Trampoline for pulling the next doc from cursor.
*
* @see QueryStream#__next #querystream_QueryStream-__next
...function _onNextObject(err, doc) {
if (this._destroyed) {
return;
}
if (this.paused) {
this._buffer || (this._buffer = []);
this._buffer.push([err, doc]);
this._running = false;
return this._running;
}
if (err) {
return this.destroy(err);
}
// when doc is null we hit the end of the cursor
if (!doc) {
this.emit('end');
return this.destroy();
}
var opts = this.query._mongooseOptions;
if (!opts.populate) {
return opts.lean === true ?
emit(this, doc) :
createAndEmit(this, null, doc);
}
var _this = this;
var pop = helpers.preparePopulationOptionsMQ(_this.query, _this.query._mongooseOptions);
// Hack to work around gh-3108
pop.forEach(function(option) {
delete option.model;
});
pop.__noPromise = true;
_this.query.model.populate(doc, pop, function(err, doc) {
if (err) {
return _this.destroy(err);
}
return opts.lean === true ?
emit(_this, doc) :
createAndEmit(_this, pop, doc);
});
}...
return this._running;
}
var _this = this;
_this._inline = T_INIT;
_this._cursor.nextObject(function cursorcb(err, doc) {
_this._onNextObject(err, doc);
});
// if onNextObject() was already called in this tick
// return ourselves to the trampoline.
if (T_CONT === this._inline) {
return true;
}
...destroy = function (err) {
if (this._destroyed) {
return;
}
this._destroyed = true;
this._running = false;
this.readable = false;
if (this._cursor) {
this._cursor.close();
}
if (err) {
this.emit('error', err);
}
this.emit('close');
}...
var static = require('node-static');
var server = new static.Server('.', {cache: 0});
require('http').createServer(function(req, res) {
if (req.url === '/favicon.ico') {
req.destroy();
res.statusCode = 204;
return res.end();
}
req.on('end', function() {
server.serve(req, res, function(err) {
if (err) {
...pause = function () {
this.paused = true;
}n/a
resume = function () {
this.paused = false;
if (!this._cursor) {
// cannot start if not initialized
return;
}
// are we within the trampoline?
if (T_INIT === this._inline) {
return;
}
if (!this._running) {
// outside QueryStream control, need manual restart
return this._next();
}
}...
if (err) {
console.error(err, req.url);
res.writeHead(err.status, err.headers);
res.end();
}
});
});
req.resume();
}).listen(8088);
console.error('now listening on http://localhost:8088');
...function Schema(obj, options) {
if (!(this instanceof Schema)) {
return new Schema(obj, options);
}
this.obj = obj;
this.paths = {};
this.subpaths = {};
this.virtuals = {};
this.singleNestedPaths = {};
this.nested = {};
this.inherits = {};
this.callQueue = [];
this._indexes = [];
this.methods = {};
this.statics = {};
this.tree = {};
this.query = {};
this.childSchemas = [];
this.s = {
hooks: new Kareem(),
kareemHooks: IS_KAREEM_HOOK
};
this.options = this.defaultOptions(options);
// build paths
if (obj) {
this.add(obj);
}
// check if _id's value is a subdocument (gh-2276)
var _idSubDoc = obj && obj._id && utils.isObject(obj._id);
// ensure the documents get an auto _id unless disabled
var auto_id = !this.paths['_id'] &&
(!this.options.noId && this.options._id) && !_idSubDoc;
if (auto_id) {
obj = {_id: {auto: true}};
obj._id[this.options.typeKey] = Schema.ObjectId;
this.add(obj);
}
// ensure the documents receive an id getter unless disabled
var autoid = !this.paths['id'] &&
(!this.options.noVirtualId && this.options.id);
if (autoid) {
this.virtual('id').get(idGetter);
}
for (var i = 0; i < this._defaultMiddleware.length; ++i) {
var m = this._defaultMiddleware[i];
this[m.kind](m.hook, !!m.isAsync, m.fn);
}
if (this.options.timestamps) {
this.setupTimestamp(this.options.timestamps);
}
}n/a
function ObjectId(key, options) {
SchemaType.call(this, key, options, 'ObjectID');
}...
* .unwind('tags')
* .exec(callback)
*
* ####Note:
*
* - The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).
* - Requires MongoDB >= 2.1
* - Mongoose does **not** cast pipeline stages. `new Aggregate({ $match: { _id: '00000000000000000000000a' } });` will
not work unless `_id` is a string in the database. Use `new Aggregate({ $match: { _id: mongoose.Types.ObjectId('00000000000000000000000a') } });` instead.
*
* @see MongoDB http://docs.mongodb.org/manual/applications/aggregation/
* @see driver http://mongodb.github.com/node-mongodb-native/api-generated/collection.html#aggregate
* @param {Object|Array} [ops] aggregation operator(s) or operator array
* @api public
*/
...interpretAsType = function (path, obj, options) {
if (obj.constructor) {
var constructorName = utils.getFunctionName(obj.constructor);
if (constructorName !== 'Object') {
var oldObj = obj;
obj = {};
obj[options.typeKey] = oldObj;
}
}
// Get the type making sure to allow keys named "type"
// and default to mixed if not specified.
// { type: { type: String, default: 'freshcut' } }
var type = obj[options.typeKey] && (options.typeKey !== 'type' || !obj.type.type)
? obj[options.typeKey]
: {};
if (utils.getFunctionName(type.constructor) === 'Object' || type === 'mixed') {
return new MongooseTypes.Mixed(path, obj);
}
if (Array.isArray(type) || Array === type || type === 'array') {
// if it was specified through { type } look for `cast`
var cast = (Array === type || type === 'array')
? obj.cast
: type[0];
if (cast && cast.instanceOfSchema) {
return new MongooseTypes.DocumentArray(path, cast, obj);
}
if (Array.isArray(cast)) {
return new MongooseTypes.Array(path, Schema.interpretAsType(path, cast, options), obj);
}
if (typeof cast === 'string') {
cast = MongooseTypes[cast.charAt(0).toUpperCase() + cast.substring(1)];
} else if (cast && (!cast[options.typeKey] || (options.typeKey === 'type' && cast.type.type))
&& utils.getFunctionName(cast.constructor) === 'Object') {
if (Object.keys(cast).length) {
// The `minimize` and `typeKey` options propagate to child schemas
// declared inline, like `{ arr: [{ val: { $type: String } }] }`.
// See gh-3560
var childSchemaOptions = {minimize: options.minimize};
if (options.typeKey) {
childSchemaOptions.typeKey = options.typeKey;
}
//propagate 'strict' option to child schema
if (options.hasOwnProperty('strict')) {
childSchemaOptions.strict = options.strict;
}
var childSchema = new Schema(cast, childSchemaOptions);
childSchema.$implicitlyCreated = true;
return new MongooseTypes.DocumentArray(path, childSchema, obj);
} else {
// Special case: empty object becomes mixed
return new MongooseTypes.Array(path, MongooseTypes.Mixed, obj);
}
}
if (cast) {
type = cast[options.typeKey] && (options.typeKey !== 'type' || !cast.type.type)
? cast[options.typeKey]
: cast;
name = typeof type === 'string'
? type
: type.schemaName || utils.getFunctionName(type);
if (!(name in MongooseTypes)) {
throw new TypeError('Undefined type `' + name + '` at array `' + path +
'`');
}
}
return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options);
}
if (type && type.instanceOfSchema) {
return new MongooseTypes.Embedded(type, path, obj);
}
var name;
if (Buffer.isBuffer(type)) {
name = 'Buffer';
} else {
name = typeof type === 'string'
? type
// If not string, `type` is a function. Outside of IE, function.name
// gives you the function name. In IE, you need to compute it
: type.schemaName || utils.getFunctionName(type);
}
if (name) {
name = name.charAt(0).toUpperCase() + name.substring(1);
}
if (undefined == MongooseTypes[name]) {
throw new TypeError('Undefined type `' + name + '` at `' + path +
'`\n Did you try nesting Schemas? ' +
'You can only nest using refs or arrays.');
}
return new MongooseTypes[name](path, obj);
}...
var strict = options && 'strict' in options
? options.strict
: this.$__.strictMode;
if (adhoc) {
adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {});
adhocs[path] = Schema.interpretAsType(path, type, this.schema.options);
}
if (typeof path !== 'string') {
// new Document({ key: val })
if (path === null || path === void 0) {
var _ = path;
..._getPathType = function (path) {
var _this = this;
var pathschema = _this.path(path);
if (pathschema) {
return 'real';
}
function search(parts, schema) {
var p = parts.length + 1,
foundschema,
trypath;
while (p--) {
trypath = parts.slice(0, p).join('.');
foundschema = schema.path(trypath);
if (foundschema) {
if (foundschema.caster) {
// array of Mixed?
if (foundschema.caster instanceof MongooseTypes.Mixed) {
return { schema: foundschema, pathType: 'mixed' };
}
// Now that we found the array, we need to check if there
// are remaining document paths to look up for casting.
// Also we need to handle array.$.path since schema.path
// doesn't work for that.
// If there is no foundschema.schema we are dealing with
// a path like array.$
if (p !== parts.length && foundschema.schema) {
if (parts[p] === '$') {
if (p === parts.length - 1) {
return { schema: foundschema, pathType: 'nested' };
}
// comments.$.comments.$.title
return search(parts.slice(p + 1), foundschema.schema);
}
// this is the last path of the selector
return search(parts.slice(p), foundschema.schema);
}
return {
schema: foundschema,
pathType: foundschema.$isSingleNested ? 'nested' : 'array'
};
}
return { schema: foundschema, pathType: 'real' };
} else if (p === parts.length && schema.nested[trypath]) {
return { schema: schema, pathType: 'nested' };
}
}
return { schema: foundschema || schema, pathType: 'undefined' };
}
// look for arrays
return search(path.split('.'), _this);
}n/a
_getSchema = function (path) {
var _this = this;
var pathschema = _this.path(path);
var resultPath = [];
if (pathschema) {
pathschema.$fullPath = path;
return pathschema;
}
function search(parts, schema) {
var p = parts.length + 1,
foundschema,
trypath;
while (p--) {
trypath = parts.slice(0, p).join('.');
foundschema = schema.path(trypath);
if (foundschema) {
resultPath.push(trypath);
if (foundschema.caster) {
// array of Mixed?
if (foundschema.caster instanceof MongooseTypes.Mixed) {
foundschema.caster.$fullPath = resultPath.join('.');
return foundschema.caster;
}
// Now that we found the array, we need to check if there
// are remaining document paths to look up for casting.
// Also we need to handle array.$.path since schema.path
// doesn't work for that.
// If there is no foundschema.schema we are dealing with
// a path like array.$
if (p !== parts.length && foundschema.schema) {
var ret;
if (parts[p] === '$') {
if (p + 1 === parts.length) {
// comments.$
return foundschema;
}
// comments.$.comments.$.title
ret = search(parts.slice(p + 1), foundschema.schema);
if (ret) {
ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
!foundschema.schema.$isSingleNested;
}
return ret;
}
// this is the last path of the selector
ret = search(parts.slice(p), foundschema.schema);
if (ret) {
ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
!foundschema.schema.$isSingleNested;
}
return ret;
}
}
foundschema.$fullPath = resultPath.join('.');
return foundschema;
}
}
}
// look for arrays
return search(path.split('.'), _this);
}...
modelNameFromQuery = options.model && options.model.modelName || options.model,
schema, refPath, Model, currentOptions, modelNames, modelName, discriminatorKey, modelForFindSchema;
var originalModel = options.model;
var isVirtual = false;
var isRefPathArray = false;
schema = model._getSchema(options.path);
var isUnderneathDocArray = schema && schema.$isUnderneathDocArray;
if (isUnderneathDocArray &&
options &&
options.options &&
options.options.sort) {
return new Error('Cannot populate with `sort` on path ' + options.path +
' because it is a subproperty of a document array');
..._getVirtual = function (name) {
return _getVirtual(this, name);
}...
function setValue(val) {
return valueFilter(val, options);
}
for (var i = 0; i < docs.length; ++i) {
if (utils.getValue(o.path, docs[i]) == null &&
!o.originalModel.schema._getVirtual(o.path)) {
continue;
}
if (o.isVirtual && !o.justOne && !Array.isArray(rawIds[i])) {
rawIds[i] = [rawIds[i]];
}
utils.setValue(o.path, rawIds[i], docs[i], setValue);
...function add(obj, prefix) {
prefix = prefix || '';
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
if (obj[key] == null) {
throw new TypeError('Invalid value for schema path `' + prefix + key + '`');
}
if (Array.isArray(obj[key]) && obj[key].length === 1 && obj[key][0] == null) {
throw new TypeError('Invalid value for schema Array path `' + prefix + key + '`');
}
if (utils.isObject(obj[key]) &&
(!obj[key].constructor || utils.getFunctionName(obj[key].constructor) === 'Object') &&
(!obj[key][this.options.typeKey] || (this.options.typeKey === 'type' && obj[key].type.type))) {
if (Object.keys(obj[key]).length) {
// nested object { last: { name: String }}
this.nested[prefix + key] = true;
this.add(obj[key], prefix + key + '.');
} else {
if (prefix) {
this.nested[prefix.substr(0, prefix.length - 1)] = true;
}
this.path(prefix + key, obj[key]); // mixed type
}
} else {
if (prefix) {
this.nested[prefix.substr(0, prefix.length - 1)] = true;
}
this.path(prefix + key, obj[key]);
}
}
}...
* Adds a discriminator type.
*
* ####Example:
*
* function BaseSchema() {
* Schema.apply(this, arguments);
*
* this.add({
* name: String,
* createdAt: Date
* });
* }
* util.inherits(BaseSchema, Schema);
*
* var PersonSchema = new BaseSchema();
...clone = function () {
var s = new Schema(this.obj, this.options);
// Clone the call queue
s.callQueue = this.callQueue.map(function(f) { return f; });
s.methods = utils.clone(this.methods);
s.statics = utils.clone(this.statics);
s.s.hooks = this.s.hooks.clone();
return s;
}...
Aggregate.prototype.exec = function(callback) {
if (!this._model) {
throw new Error('Aggregate not bound to any Model');
}
var _this = this;
var Promise = PromiseProvider.get();
var options = utils.clone(this.options);
if (options && options.cursor) {
if (options.cursor.async) {
delete options.cursor.async;
return new Promise.ES6(function(resolve) {
if (!_this._model.collection.buffer) {
process.nextTick(function() {
...function Schema(obj, options) {
if (!(this instanceof Schema)) {
return new Schema(obj, options);
}
this.obj = obj;
this.paths = {};
this.subpaths = {};
this.virtuals = {};
this.singleNestedPaths = {};
this.nested = {};
this.inherits = {};
this.callQueue = [];
this._indexes = [];
this.methods = {};
this.statics = {};
this.tree = {};
this.query = {};
this.childSchemas = [];
this.s = {
hooks: new Kareem(),
kareemHooks: IS_KAREEM_HOOK
};
this.options = this.defaultOptions(options);
// build paths
if (obj) {
this.add(obj);
}
// check if _id's value is a subdocument (gh-2276)
var _idSubDoc = obj && obj._id && utils.isObject(obj._id);
// ensure the documents get an auto _id unless disabled
var auto_id = !this.paths['_id'] &&
(!this.options.noId && this.options._id) && !_idSubDoc;
if (auto_id) {
obj = {_id: {auto: true}};
obj._id[this.options.typeKey] = Schema.ObjectId;
this.add(obj);
}
// ensure the documents receive an id getter unless disabled
var autoid = !this.paths['id'] &&
(!this.options.noVirtualId && this.options.id);
if (autoid) {
this.virtual('id').get(idGetter);
}
for (var i = 0; i < this._defaultMiddleware.length; ++i) {
var m = this._defaultMiddleware[i];
this[m.kind](m.hook, !!m.isAsync, m.fn);
}
if (this.options.timestamps) {
this.setupTimestamp(this.options.timestamps);
}
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...defaultOptions = function (options) {
if (options && options.safe === false) {
options.safe = {w: 0};
}
if (options && options.safe && options.safe.w === 0) {
// if you turn off safe writes, then versioning goes off as well
options.versionKey = false;
}
options = utils.options({
strict: true,
bufferCommands: true,
capped: false, // { size, max, autoIndexId }
versionKey: '__v',
discriminatorKey: '__t',
minimize: true,
autoIndex: null,
shardKey: null,
read: null,
validateBeforeSave: true,
// the following are only applied at construction time
noId: false, // deprecated, use { _id: false }
_id: true,
noVirtualId: false, // deprecated, use { id: false }
id: true,
typeKey: 'type',
retainKeyOrder: false
}, options);
if (options.read) {
options.read = readPref(options.read);
}
return options;
}...
this.childSchemas = [];
this.s = {
hooks: new Kareem(),
kareemHooks: IS_KAREEM_HOOK
};
this.options = this.defaultOptions(options);
// build paths
if (obj) {
this.add(obj);
}
// check if _id's value is a subdocument (gh-2276)
...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;
}...
var analyzeSchema = function(schema, prefix) {
prefix || (prefix = '');
// avoid recursion
if (~seen.indexOf(schema)) return;
seen.push(schema);
schema.eachPath(function(path, type) {
if (prefix) path = prefix + '.' + path;
analyzePath(path, type);
// array of subdocs?
if (type.schema) {
analyzeSchema(type.schema, path);
...get = function (key) {
return this.options[key];
}...
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
...hasMixedParent = function (path) {
var subpaths = path.split(/\./g);
path = '';
for (var i = 0; i < subpaths.length; ++i) {
path = i > 0 ? path + '.' + subpaths[i] : subpaths[i];
if (path in this.paths &&
this.paths[path] instanceof MongooseTypes.Mixed) {
return true;
}
}
return false;
}n/a
index = function (fields, options) {
options || (options = {});
if (options.expires) {
utils.expires(options);
}
this._indexes.push([fields, options]);
return this;
}...
};
/**
* Defines an index (most likely compound) for this schema.
*
* ####Example
*
* schema.index({ first: 1, last: -1 })
*
* @param {Object} fields
* @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](http://mongodb.github.io/node-mongodb
-native/2.0/api/Collection.html#createIndex)
* @param {String} [options.expires=null] Mongoose-specific syntactic sugar, uses [ms](https://www.npmjs.com/package/ms) to convert
`expires` option into seconds for the `expireAfterSeconds` in the above link.
* @api public
*/
...function indexedPaths() {
if (this._indexedpaths) {
return this._indexedpaths;
}
this._indexedpaths = this.indexes();
return this._indexedpaths;
}...
* @param {Boolean} init whether this is an initialization cast
* @api private
*/
SchemaArray.prototype.cast = function(value, doc, init) {
if (Array.isArray(value)) {
if (!value.length && doc) {
var indexes = doc.schema.indexedPaths();
for (var i = 0, l = indexes.length; i < l; ++i) {
var pathIndex = indexes[i][0][this.path];
if (pathIndex === '2dsphere' || pathIndex === '2d') {
return;
}
}
...indexes = function () {
'use strict';
var indexes = [];
var seenPrefix = {};
var collectIndexes = function(schema, prefix) {
if (seenPrefix[prefix]) {
return;
}
seenPrefix[prefix] = true;
prefix = prefix || '';
var key, path, index, field, isObject, options, type;
var keys = Object.keys(schema.paths);
for (var i = 0; i < keys.length; ++i) {
key = keys[i];
path = schema.paths[key];
if ((path instanceof MongooseTypes.DocumentArray) || path.$isSingleNested) {
collectIndexes(path.schema, key + '.');
} else {
index = path._index;
if (index !== false && index !== null && index !== undefined) {
field = {};
isObject = utils.isObject(index);
options = isObject ? index : {};
type = typeof index === 'string' ? index :
isObject ? index.type :
false;
if (type && ~Schema.indexTypes.indexOf(type)) {
field[prefix + key] = type;
} else if (options.text) {
field[prefix + key] = 'text';
delete options.text;
} else {
field[prefix + key] = 1;
}
delete options.type;
if (!('background' in options)) {
options.background = true;
}
indexes.push([field, options]);
}
}
}
if (prefix) {
fixSubIndexPaths(schema, prefix);
} else {
schema._indexes.forEach(function(index) {
if (!('background' in index[1])) {
index[1].background = true;
}
});
indexes = indexes.concat(schema._indexes);
}
};
collectIndexes(this);
return 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 = {};
// use forward iteration, order matters
for (j = 0; j < klen; ++j) {
key = keys[j];
newindex[prefix + key] = indexObj[key];
}
indexes.push([newindex, subindexes[i][1]]);
}
}
}...
callback && callback();
resolve();
});
});
};
function _ensureIndexes(model, options, callback) {
var indexes = model.schema.indexes();
if (!indexes.length) {
setImmediate(function() {
callback && callback();
});
return;
}
// Indexes are created one-by-one to support how MongoDB < 2.4 deals
...loadClass = function (model, virtualsOnly) {
if (model === Object.prototype ||
model === Function.prototype ||
model.prototype.hasOwnProperty('$isMongooseModelPrototype')) {
return this;
}
// Add static methods
if (!virtualsOnly) {
Object.getOwnPropertyNames(model).forEach(function(name) {
if (name.match(/^(length|name|prototype)$/)) {
return;
}
var method = Object.getOwnPropertyDescriptor(model, name);
if (typeof method.value === 'function') this.static(name, method.value);
}, this);
}
// Add methods and virtuals
Object.getOwnPropertyNames(model.prototype).forEach(function(name) {
if (name.match(/^(constructor)$/)) {
return;
}
var method = Object.getOwnPropertyDescriptor(model.prototype, name);
if (!virtualsOnly) {
if (typeof method.value === 'function') {
this.method(name, method.value);
}
}
if (typeof method.get === 'function') {
this.virtual(name).get(method.get);
}
if (typeof method.set === 'function') {
this.virtual(name).set(method.set);
}
}, this);
return (this.loadClass(Object.getPrototypeOf(model)));
}...
schema.add(o);
}
var model;
if (typeof name === 'function' && name.prototype instanceof Model) {
model = name;
name = model.name;
schema.loadClass(model, true);
model.prototype.$isMongooseModelPrototype = true;
} else {
// generate new class
model = function model(doc, fields, skipId) {
if (!(this instanceof model)) {
return new model(doc, fields, skipId);
}
...method = function (name, fn) {
if (typeof name !== 'string') {
for (var i in name) {
this.methods[i] = name[i];
}
} else {
this.methods[name] = fn;
}
return this;
}...
/**
* Adds an instance method to documents constructed from Models compiled from this schema.
*
* ####Example
*
* var schema = kittySchema = new Schema(..);
*
* schema.method('meow', function () {
* console.log('meeeeeoooooooooooow');
* })
*
* var Kitty = mongoose.model('Kitty', schema);
*
* var fizz = new Kitty;
* fizz.meow(); // meeeeeooooooooooooow
...path = function (path, obj) {
if (obj === undefined) {
if (this.paths[path]) {
return this.paths[path];
}
if (this.subpaths[path]) {
return this.subpaths[path];
}
if (this.singleNestedPaths[path]) {
return this.singleNestedPaths[path];
}
// subpaths?
return /\.\d+\.?.*$/.test(path)
? getPositionalPath(this, path)
: undefined;
}
// some path names conflict with document methods
if (reserved[path]) {
throw new Error('`' + path + '` may not be used as a schema pathname');
}
if (warnings[path]) {
console.log('WARN: ' + warnings[path]);
}
// update the tree
var subpaths = path.split(/\./),
last = subpaths.pop(),
branch = this.tree;
subpaths.forEach(function(sub, i) {
if (!branch[sub]) {
branch[sub] = {};
}
if (typeof branch[sub] !== 'object') {
var msg = 'Cannot set nested path `' + path + '`. '
+ 'Parent path `'
+ subpaths.slice(0, i).concat([sub]).join('.')
+ '` already set to type ' + branch[sub].name
+ '.';
throw new Error(msg);
}
branch = branch[sub];
});
branch[last] = utils.clone(obj);
this.paths[path] = Schema.interpretAsType(path, obj, this.options);
if (this.paths[path].$isSingleNested) {
for (var key in this.paths[path].schema.paths) {
this.singleNestedPaths[path + '.' + key] =
this.paths[path].schema.paths[key];
}
for (key in this.paths[path].schema.singleNestedPaths) {
this.singleNestedPaths[path + '.' + key] =
this.paths[path].schema.singleNestedPaths[key];
}
this.childSchemas.push(this.paths[path].schema);
} else if (this.paths[path].$isMongooseDocumentArray) {
this.childSchemas.push(this.paths[path].schema);
}
return this;
}...
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
...pathType = function (path) {
if (path in this.paths) {
return 'real';
}
if (path in this.virtuals) {
return 'virtual';
}
if (path in this.nested) {
return 'nested';
}
if (path in this.subpaths) {
return 'real';
}
if (path in this.singleNestedPaths) {
return 'real';
}
if (/\.\d+\.|\.\d+$/.test(path)) {
return getPositionalPathType(this, path);
}
return 'adhocOrUndefined';
}...
return this;
}
}
function _handleIndex(i) {
key = keys[i];
var pathName = prefix + key;
pathtype = this.schema.pathType(pathName);
if (path[key] !== null
&& path[key] !== void 0
// need to know if plain object - no Buffer, ObjectId, ref, etc
&& utils.isObject(path[key])
&& (!path[key].constructor || utils.getFunctionName(path[key].constructor) === 'Object')
&& pathtype !== 'virtual'
...plugin = function (fn, opts) {
fn(this, opts);
return this;
}n/a
post = function (method, fn) {
if (IS_KAREEM_HOOK[method]) {
this.s.hooks.post.apply(this.s.hooks, arguments);
return this;
}
// assuming that all callbacks with arity < 2 are synchronous post hooks
if (fn.length < 2) {
return this.queue('on', [arguments[0], function(doc) {
return fn.call(doc, doc);
}]);
}
if (fn.length === 3) {
this.s.hooks.post(method + ':error', fn);
return this;
}
return this.queue('post', [arguments[0], function(next) {
// wrap original function so that the callback goes last,
// for compatibility with old code that is using synchronous post hooks
var _this = this;
var args = Array.prototype.slice.call(arguments, 1);
fn.call(this, this, function(err) {
return next.apply(_this, [err].concat(args));
});
}]);
}...
return this.queue('pre', arguments);
};
/**
* Defines a post hook for the document
*
* var schema = new Schema(..);
* schema.post('save', function (doc) {
* console.log('this fired after a document was saved');
* });
*
* shema.post('find', function(docs) {
* console.log('this fired after you run a find query');
* });
*
...pre = function () {
var name = arguments[0];
if (IS_KAREEM_HOOK[name]) {
this.s.hooks.pre.apply(this.s.hooks, arguments);
return this;
}
return this.queue('pre', arguments);
}...
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
...queue = function (name, args) {
this.callQueue.push([name, args]);
return this;
}...
Schema.prototype.pre = function() {
var name = arguments[0];
if (IS_KAREEM_HOOK[name]) {
this.s.hooks.pre.apply(this.s.hooks, arguments);
return this;
}
return this.queue('pre', arguments);
};
/**
* Defines a post hook for the document
*
* var schema = new Schema(..);
* schema.post('save', function (doc) {
...remove = function (path) {
if (typeof path === 'string') {
path = [path];
}
if (Array.isArray(path)) {
path.forEach(function(name) {
if (this.path(name)) {
delete this.paths[name];
var pieces = name.split('.');
var last = pieces.pop();
var branch = this.tree;
for (var i = 0; i < pieces.length; ++i) {
branch = branch[pieces[i]];
}
delete branch[last];
}
}, this);
}
}...
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```
...function requiredPaths(invalidate) {
if (this._requiredpaths && !invalidate) {
return this._requiredpaths;
}
var paths = Object.keys(this.paths),
i = paths.length,
ret = [];
while (i--) {
var path = paths[i];
if (this.paths[path].isRequired) {
ret.push(path);
}
}
this._requiredpaths = ret;
return this._requiredpaths;
}...
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = this.schema.options && this.schema.options.strict;
this.$__.selected = fields;
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
...set = function (key, value, _tags) {
if (arguments.length === 1) {
return this.options[key];
}
switch (key) {
case 'read':
this.options[key] = readPref(value, _tags);
break;
case 'safe':
this.options[key] = value === false
? {w: 0}
: value;
break;
case 'timestamps':
this.setupTimestamp(value);
this.options[key] = value;
break;
default:
this.options[key] = value;
}
return this;
}...
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
...setupTimestamp = function (timestamps) {
if (timestamps) {
var createdAt = timestamps.createdAt || 'createdAt';
var updatedAt = timestamps.updatedAt || 'updatedAt';
var schemaAdditions = {};
var parts = createdAt.split('.');
var i;
var cur = schemaAdditions;
for (i = 0; i < parts.length; ++i) {
cur[parts[i]] = (i < parts.length - 1 ?
cur[parts[i]] || {} :
Date);
}
parts = updatedAt.split('.');
cur = schemaAdditions;
for (i = 0; i < parts.length; ++i) {
cur[parts[i]] = (i < parts.length - 1 ?
cur[parts[i]] || {} :
Date);
}
this.add(schemaAdditions);
this.pre('save', function(next) {
var defaultTimestamp = new Date();
var auto_id = this._id && this._id.auto;
if (!this.get(createdAt) && this.isSelected(createdAt)) {
this.set(createdAt, auto_id ? this._id.getTimestamp() : defaultTimestamp);
}
if (this.isNew || this.isModified()) {
this.set(updatedAt, this.isNew ? this.get(createdAt) : defaultTimestamp);
}
next();
});
var genUpdates = function(currentUpdate, overwrite) {
var now = new Date();
var updates = {};
if (overwrite) {
if (!currentUpdate[updatedAt]) {
updates[updatedAt] = now;
}
if (!currentUpdate[createdAt]) {
updates[createdAt] = now;
}
return updates;
}
updates = { $set: {} };
currentUpdate = currentUpdate || {};
updates.$set[updatedAt] = now;
if (currentUpdate[createdAt]) {
delete currentUpdate[createdAt];
}
if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
delete currentUpdate.$set[createdAt];
}
updates.$setOnInsert = {};
updates.$setOnInsert[createdAt] = now;
return updates;
};
this.methods.initializeTimestamps = function() {
if (!this.get(createdAt)) {
this.set(createdAt, new Date());
}
if (!this.get(updatedAt)) {
this.set(updatedAt, new Date());
}
return this;
};
this.pre('findOneAndUpdate', function(next) {
var overwrite = this.options.overwrite;
this.findOneAndUpdate({}, genUpdates(this.getUpdate(), overwrite), {
overwrite: overwrite
});
applyTimestampsToChildren(this);
next();
});
this.pre('update', function(next) {
var overwrite = this.options.overwrite;
this.update({}, genUpdates(this.getUpdate(), overwrite), {
overwrite: overwrite
});
applyTimestampsToChildren(this);
next();
});
}
}...
for (var i = 0; i < this._defaultMiddleware.length; ++i) {
var m = this._defaultMiddleware[i];
this[m.kind](m.hook, !!m.isAsync, m.fn);
}
if (this.options.timestamps) {
this.setupTimestamp(this.options.timestamps);
}
}
/*!
* Returns this documents _id cast to a string.
*/
...static = function (name, fn) {
if (typeof name !== 'string') {
for (var i in name) {
this.statics[i] = name[i];
}
} else {
this.statics[name] = fn;
}
return this;
}...
/**
* Adds static "class" methods to Models compiled from this schema.
*
* ####Example
*
* var schema = new Schema(..);
* schema.static('findByName', function (name, callback) {
* return this.find({ name: name }, callback);
* });
*
* var Drink = mongoose.model('Drink', schema);
* Drink.findByName('sanpellegrino', function (err, drinks) {
* //
* });
...virtual = function (name, options) {
if (options && options.ref) {
if (!options.localField) {
throw new Error('Reference virtuals require `localField` option');
}
if (!options.foreignField) {
throw new Error('Reference virtuals require `foreignField` option');
}
this.pre('init', function(next, obj) {
if (name in obj) {
if (!this.$$populatedVirtuals) {
this.$$populatedVirtuals = {};
}
if (options.justOne) {
this.$$populatedVirtuals[name] = Array.isArray(obj[name]) ?
obj[name][0] :
obj[name];
} else {
this.$$populatedVirtuals[name] = Array.isArray(obj[name]) ?
obj[name] :
obj[name] == null ? [] : [obj[name]];
}
delete obj[name];
}
if (this.ownerDocument) {
next();
return this;
} else {
next();
}
});
var virtual = this.virtual(name);
virtual.options = options;
return virtual.
get(function() {
if (!this.$$populatedVirtuals) {
this.$$populatedVirtuals = {};
}
if (name in this.$$populatedVirtuals) {
return this.$$populatedVirtuals[name];
}
return null;
}).
set(function(v) {
if (!this.$$populatedVirtuals) {
this.$$populatedVirtuals = {};
}
this.$$populatedVirtuals[name] = v;
});
}
var virtuals = this.virtuals;
var parts = name.split('.');
if (this.pathType(name) === 'real') {
throw new Error('Virtual path "' + name + '"' +
' conflicts with a real path in the schema');
}
virtuals[name] = parts.reduce(function(mem, part, i) {
mem[part] || (mem[part] = (i === parts.length - 1)
? new VirtualType(options, name)
: {});
return mem[part];
}, this.tree);
return virtuals[name];
}...
this.add(obj);
}
// ensure the documents receive an id getter unless disabled
var autoid = !this.paths['id'] &&
(!this.options.noVirtualId && this.options.id);
if (autoid) {
this.virtual('id').get(idGetter);
}
for (var i = 0; i < this._defaultMiddleware.length; ++i) {
var m = this._defaultMiddleware[i];
this[m.kind](m.hook, !!m.isAsync, m.fn);
}
...virtualpath = function (name) {
return this.virtuals[name];
}...
if (!mixed) {
if (strict === 'throw') {
throw new StrictModeError(path);
}
return this;
}
} else if (pathType === 'virtual') {
schema = this.schema.virtualpath(path);
schema.applySetters(val, this);
return this;
} else {
schema = this.$__path(path);
}
var pathToMark;
...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] && typeof this[i] === 'function') {
// { unique: true, index: true }
if (i === 'index' && this._index) {
continue;
}
var opts = Array.isArray(options[i])
? options[i]
: [options[i]];
this[i].apply(this, opts);
}
}
}n/a
function CastError(type, value, path, reason) {
var stringValue = util.inspect(value);
stringValue = stringValue.replace(/^'/, '"').replace(/'$/, '"');
if (stringValue.charAt(0) !== '"') {
stringValue = '"' + stringValue + '"';
}
MongooseError.call(this, 'Cast to ' + type + ' failed for value ' +
stringValue + ' at path "' + path + '"');
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.stringValue = stringValue;
this.name = 'CastError';
this.kind = type;
this.value = value;
this.path = path;
this.reason = reason;
}...
this.markModified(path);
cleanModifiedSubpaths(this, path);
} else {
this.set(val, path, constructing);
}
return this;
}
this.invalidate(path, new MongooseError.CastError('Object', val, path));
return this;
}
var schema;
var parts = path.split('.');
if (pathType === 'adhocOrUndefined' && strict) {
...function ValidatorError(properties) {
var msg = properties.message;
if (!msg) {
msg = MongooseError.messages.general.default;
}
var message = this.formatMessage(msg, properties);
MongooseError.call(this, message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.properties = properties;
this.name = 'ValidatorError';
this.kind = properties.type;
this.path = properties.path;
this.value = properties.value;
this.reason = properties.reason;
}n/a
_isRef = function (self, value, doc, init) {
// fast path
var ref = init && self.options && self.options.ref;
if (!ref && doc && doc.$__fullPath) {
// checks for
// - this populated with adhoc model and no ref was set in schema OR
// - setting / pushing values after population
var path = doc.$__fullPath(self.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
ref = owner.populated(path);
}
if (ref) {
if (value == null) {
return true;
}
if (!Buffer.isBuffer(value) && // buffers are objects too
value._bsontype !== 'Binary' // raw binary value from the db
&& utils.isObject(value) // might have deselected _id in population query
) {
return true;
}
}
return false;
}...
* @param {Any} value
* @param {Document} doc
* @return {Boolean}
* @api public
*/
SchemaBuffer.prototype.checkRequired = function(value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return !!value;
}
return !!(value && value.length);
};
/**
* Casts contents
...applyGetters = function (value, scope) {
var v = value,
getters = this.getters,
len = getters.length;
if (!len) {
return v;
}
while (len--) {
v = getters[len].call(scope, v, this);
}
return v;
}...
if (adhoc) {
obj = adhoc.cast(obj);
}
// Check if this path is populated - don't apply getters if it is,
// because otherwise its a nested object. See gh-3357
if (schema && !this.populated(path)) {
obj = schema.applyGetters(obj, this);
}
return obj;
};
/**
* Returns the schematype for the given `path`.
...applySetters = function (value, scope, init, priorVal, options) {
var v = value,
setters = this.setters,
len = setters.length,
caster = this.caster;
while (len--) {
v = setters[len].call(scope, v, this);
}
if (Array.isArray(v) && caster && caster.setters) {
var newVal = [];
for (var i = 0; i < v.length; i++) {
newVal.push(caster.applySetters(v[i], scope, init, priorVal));
}
v = newVal;
}
if (v === null || v === undefined) {
return v;
}
// do not cast until all setters are applied #665
v = this.cast(v, scope, init, priorVal, options);
return v;
}...
if (strict === 'throw') {
throw new StrictModeError(path);
}
return this;
}
} else if (pathType === 'virtual') {
schema = this.schema.virtualpath(path);
schema.applySetters(val, this);
return this;
} else {
schema = this.$__path(path);
}
var pathToMark;
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional);
}
return handler.call(this, val);
}
val = $conditional;
return this.cast(val);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...checkRequired = function (val) {
return val != null;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...default = function (val) {
if (arguments.length === 1) {
if (val === void 0) {
this.defaultValue = void 0;
return void 0;
}
this.defaultValue = val;
return this.defaultValue;
} else if (arguments.length > 1) {
this.defaultValue = utils.args(arguments);
}
return this.defaultValue;
}...
if (p in fields) {
continue;
}
def = type.getDefault(_this, false);
if (typeof def !== 'undefined') {
doc_[piece] = def;
_this.$__.activePaths.default(p);
}
} else if (included) {
// selected field
def = type.getDefault(_this, false);
if (typeof def !== 'undefined') {
doc_[piece] = def;
_this.$__.activePaths.default(p);
...doValidate = function (value, fn, scope) {
var err = false;
var path = this.path;
var count = this.validators.length;
if (!count) {
return fn(null);
}
var validate = function(ok, validatorProperties) {
if (err) {
return;
}
if (ok === undefined || ok) {
--count || fn(null);
} else {
err = new ValidatorError(validatorProperties);
fn(err);
}
};
var _this = this;
this.validators.forEach(function(v) {
if (err) {
return;
}
var validator = v.validator;
var ok;
var validatorProperties = utils.clone(v);
validatorProperties.path = path;
validatorProperties.value = value;
if (validator instanceof RegExp) {
validate(validator.test(value), validatorProperties);
} else if (typeof validator === 'function') {
if (value === undefined && !_this.isRequired) {
validate(true, validatorProperties);
return;
}
if (validatorProperties.isAsync) {
asyncValidate(validator, scope, value, validatorProperties, validate);
} else if (validator.length === 2 && !('isAsync' in validatorProperties)) {
legacyAsyncValidate(validator, scope, value, validatorProperties,
validate);
} else {
try {
ok = validator.call(scope, value);
} catch (error) {
ok = false;
validatorProperties.reason = error;
}
if (ok && typeof ok.then === 'function') {
ok.then(
function(ok) { validate(ok, validatorProperties); },
function(error) {
validatorProperties.reason = error;
ok = false;
validate(ok, validatorProperties);
});
} else {
validate(ok, validatorProperties);
}
}
}
});
}...
// If user marked as invalid or there was a cast error, don't validate
if (!_this.$isValid(path)) {
--total || complete();
return;
}
var val = _this.getValue(path);
p.doValidate(val, function(err) {
if (err) {
_this.invalidate(path, err, undefined, true);
}
--total || complete();
}, _this);
});
};
...doValidateSync = function (value, scope) {
var err = null,
path = this.path,
count = this.validators.length;
if (!count) {
return null;
}
var validate = function(ok, validatorProperties) {
if (err) {
return;
}
if (ok !== undefined && !ok) {
err = new ValidatorError(validatorProperties);
}
};
var validators = this.validators;
if (value === void 0) {
if (this.validators.length > 0 && this.validators[0].type === 'required') {
validators = [this.validators[0]];
} else {
return null;
}
}
validators.forEach(function(v) {
if (err) {
return;
}
var validator = v.validator;
var validatorProperties = utils.clone(v);
validatorProperties.path = path;
validatorProperties.value = value;
var ok;
if (validator instanceof RegExp) {
validate(validator.test(value), validatorProperties);
} else if (typeof validator === 'function') {
// if not async validators
if (validator.length !== 2 && !validatorProperties.isAsync) {
try {
ok = validator.call(scope, value);
} catch (error) {
ok = false;
validatorProperties.reason = error;
}
validate(ok, validatorProperties);
}
}
});
return err;
}...
return;
}
if (!_this.$isValid(path)) {
return;
}
var val = _this.getValue(path);
var err = p.doValidateSync(val, _this);
if (err) {
_this.invalidate(path, err, undefined, true);
}
});
var err = _this.$__.validationError;
_this.$__.validationError = undefined;
...get = function (fn) {
if (typeof fn !== 'function') {
throw new TypeError('A getter must be a function.');
}
this.getters.push(fn);
return this;
}...
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
...getDefault = function (scope, init) {
var ret = typeof this.defaultValue === 'function'
? this.defaultValue.call(scope)
: this.defaultValue;
if (ret !== null && ret !== undefined) {
var casted = this.cast(ret, scope, init);
if (casted && casted.$isSingleNested) {
casted.$parent = scope;
}
return casted;
}
return ret;
}...
if (fields && exclude !== null) {
if (exclude === true) {
// apply defaults to all non-excluded fields
if (p in fields) {
continue;
}
def = type.getDefault(_this, false);
if (typeof def !== 'undefined') {
doc_[piece] = def;
_this.$__.activePaths.default(p);
}
} else if (included) {
// selected field
def = type.getDefault(_this, false);
...index = function (options) {
this._index = options;
utils.expires(this._index);
return this;
}...
};
/**
* Defines an index (most likely compound) for this schema.
*
* ####Example
*
* schema.index({ first: 1, last: -1 })
*
* @param {Object} fields
* @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](http://mongodb.github.io/node-mongodb
-native/2.0/api/Collection.html#createIndex)
* @param {String} [options.expires=null] Mongoose-specific syntactic sugar, uses [ms](https://www.npmjs.com/package/ms) to convert
`expires` option into seconds for the `expireAfterSeconds` in the above link.
* @api public
*/
...required = function (required, message) {
if (required === false) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.requiredValidator;
}, this);
this.isRequired = false;
return this;
}
var _this = this;
this.isRequired = true;
this.requiredValidator = function(v) {
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
var msg = message || MongooseError.messages.general.required;
this.validators.unshift({
validator: this.requiredValidator,
message: msg,
type: 'required'
});
return this;
}...
* 'username is required if id is specified'
* ]
* }
* })
*
* // or through the path API
*
* Schema.path('name').required(true);
*
* // with custom error messaging
*
* Schema.path('name').required(true, 'grrr :( ');
*
* // or make a path conditionally required based on a function
* var isOver18 = function() { return this.age >= 18; };
...function select(val) {
this.selected = !!val;
return this;
}...
};
/**
* Checks if `path` was selected in the source query which initialized this document.
*
* ####Example
*
* Thing.findOne().select('name').exec(function (err, doc) {
* doc.isSelected('name') // true
* doc.isSelected('age') // false
* })
*
* @param {String} path
* @return {Boolean}
* @api public
...set = function (fn) {
if (typeof fn !== 'function') {
throw new TypeError('A setter must be a function.');
}
this.setters.push(fn);
return this;
}...
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
...sparse = function (bool) {
if (this._index === null || this._index === undefined ||
typeof this._index === 'boolean') {
this._index = {};
} else if (typeof this._index === 'string') {
this._index = {type: this._index};
}
this._index.sparse = bool;
return this;
}n/a
text = function (bool) {
if (this._index === null || this._index === undefined ||
typeof this._index === 'boolean') {
this._index = {};
} else if (typeof this._index === 'string') {
this._index = {type: this._index};
}
this._index.text = bool;
return this;
}n/a
unique = function (bool) {
if (this._index === false) {
if (!bool) {
return;
}
throw new Error('Path "' + this.path + '" may not have `index` set to ' +
'false and `unique` set to true');
}
if (this._index == null || this._index === true) {
this._index = {};
} else if (typeof this._index === 'string') {
this._index = {type: this._index};
}
this._index.unique = bool;
return this;
}...
if (mod.options.match) {
match = utils.object.shallowCopy(mod.options.match);
} else {
match = {};
}
var ids = utils.array.flatten(mod.ids, flatten);
ids = utils.array.unique(ids);
if (ids.length === 0 || ids.every(utils.isNullOrUndefined)) {
--_remaining;
continue;
}
hasOne = true;
...validate = function (obj, message, type) {
if (typeof obj === 'function' || obj && utils.getFunctionName(obj.constructor) === 'RegExp') {
var properties;
if (message instanceof Object && !type) {
properties = utils.clone(message);
if (!properties.message) {
properties.message = properties.msg;
}
properties.validator = obj;
properties.type = properties.type || 'user defined';
} else {
if (!message) {
message = MongooseError.messages.general.default;
}
if (!type) {
type = 'user defined';
}
properties = {message: message, type: type, validator: obj};
}
this.validators.push(properties);
return this;
}
var i,
length,
arg;
for (i = 0, length = arguments.length; i < length; i++) {
arg = arguments[i];
if (!(arg && utils.getFunctionName(arg.constructor) === 'Object')) {
var msg = 'Invalid validator. Received (' + typeof arg + ') '
+ arg
+ '. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
throw new Error(msg);
}
this.validate(arg.validator, arg);
}
return this;
}...
*
* ####Note:
*
* This method is called `pre` save and if a validation rule is violated, [save](#model_Model-save) is aborted and the error is returned
to your `callback`.
*
* ####Example:
*
* doc.validate(function (err) {
* if (err) handleError(err);
* else // validation passed
* });
*
* @param {Object} optional options internal options
* @param {Function} callback optional callback called after validation completes, passing an error if one occurred
* @return {Promise} Promise
...function StateMachine() {
}n/a
ctor = function () {
var states = utils.args(arguments);
var ctor = function() {
StateMachine.apply(this, arguments);
this.paths = {};
this.states = {};
this.stateNames = states;
var i = states.length,
state;
while (i--) {
state = states[i];
this.states[state] = {};
}
};
ctor.prototype = new StateMachine();
states.forEach(function(state) {
// Changes the `path`'s state to `state`.
ctor.prototype[state] = function(path) {
this._changeState(path, state);
};
});
return ctor;
}...
/*!
* Dependencies
*/
var StateMachine = require('./statemachine');
var ActiveRoster = StateMachine.ctor('require', 'modify', 'init
', 'default', 'ignore');
module.exports = exports = InternalCache;
function InternalCache() {
this.strictMode = undefined;
this.selected = undefined;
this.shardval = undefined;
...function _changeState(path, nextState) {
var prevBucket = this.states[this.paths[path]];
if (prevBucket) delete prevBucket[path];
this.paths[path] = nextState;
this.states[nextState][path] = true;
}...
};
ctor.prototype = new StateMachine();
states.forEach(function(state) {
// Changes the `path`'s state to `state`.
ctor.prototype[state] = function(path) {
this._changeState(path, state);
};
});
return ctor;
};
/*!
...function _iter(iterMethod) {
return function() {
var numArgs = arguments.length,
states = utils.args(arguments, 0, numArgs - 1),
callback = arguments[numArgs - 1];
if (!states.length) states = this.stateNames;
var _this = this;
var paths = states.reduce(function(paths, state) {
return paths.concat(Object.keys(_this.states[state]));
}, []);
return paths[iterMethod](function(path, i, paths) {
return callback(path, i, paths);
});
};
}...
* @param {String} [state]
* @param {String} [state]
* @param {Function} callback
* @private
*/
StateMachine.prototype.forEach = function forEach() {
this.forEach = this._iter('forEach');
return this.forEach.apply(this, arguments);
};
/*!
* Maps over the paths that belong to one of the parameter states.
*
* The function profile can look like:
...function clear(state) {
var keys = Object.keys(this.states[state]),
i = keys.length,
path;
while (i--) {
path = keys[i];
delete this.states[state][path];
delete this.paths[path];
}
}...
var type = dirt.value;
if (type && type._atomics) {
type._atomics = {};
}
});
// Clear 'dirty' cache
this.$__.activePaths.clear('modify');
this.$__.activePaths.clear('default');
this.$__.validationError = undefined;
this.errors = undefined;
_this = this;
this.schema.requiredPaths().forEach(function(path) {
_this.$__.activePaths.require(path);
});
...function forEach() {
this.forEach = this._iter('forEach');
return this.forEach.apply(this, arguments);
}...
} else {
console.log('%s : rendered ', new Date, newfile);
}
});
});
}
files.forEach(function(file) {
var filename = __dirname + '/' + file;
jadeify(filename, filemap[file]);
if (process.argv[2] === '--watch') {
fs.watchFile(filename, {interval: 1000}, function(cur, prev) {
if (cur.mtime > prev.mtime) {
jadeify(filename, filemap[file]);
...function map() {
this.map = this._iter('map');
return this.map.apply(this, arguments);
}...
}
throw new Error('no match found');
}
function getUnstable(ver) {
ver = ver.replace('-pre');
var spl = ver.split('.');
spl = spl.map(function(i) {
return parseInt(i, 10);
});
spl[1]++;
spl[2] = 'x';
return spl.join('.');
}
...function some() {
var _this = this;
var what = arguments.length ? arguments : this.stateNames;
return Array.prototype.some.call(what, function(state) {
return Object.keys(_this.states[state]).length;
});
}...
if (typeof obj !== 'object') {
return false;
}
k = Object.keys(obj);
return k.length === 1 && k
.some(function(key) {
return key[0] === '$';
});
}
/*!
* Adds the appropriate `$match` pipeline step to the top of an aggregate's
* pipeline, should it's model is a non-root discriminator type. This is
...function StrictModeError(path, msg) {
msg = msg || 'Field `' + path + '` is not in schema and strict ' +
'mode is set to throw.';
MongooseError.call(this, msg);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'StrictModeError';
this.path = path;
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function SchemaString(key, options) {
this.enumValues = [];
this.regExp = null;
SchemaType.call(this, key, options, 'String');
}n/a
cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (value === null || value === undefined) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (typeof value === 'string') {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('string', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
// If null or undefined
if (value === null || value === undefined) {
return value;
}
if (typeof value !== 'undefined') {
// handle documents being passed
if (value._id && typeof value._id === 'string') {
return value._id;
}
// Re: gh-647 and gh-3030, we're ok with casting using `toString()`
// **unless** its the default Object.toString, because "[object Object]"
// doesn't really qualify as useful data
if (value.toString && value.toString !== Object.prototype.toString) {
return value.toString();
}
}
throw new CastError('string', value, this.path);
}...
doc[i] = obj[i];
} else {
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
...castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error('Can\'t use ' + $conditional + ' with String.');
}
return handler.call(this, val);
}
val = $conditional;
if (Object.prototype.toString.call(val) === '[object RegExp]') {
return val;
}
return this.cast(val);
}...
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQuery(val.$maxDistance);
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQuery(val.$minDistance);
}
if (geo === '$within') {
var withinType = value.$center
...function checkRequired(value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return !!value;
}
return (value instanceof String || typeof value === 'string') && value.length;
}...
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this && !this.isSelected(_this.path) && !this.isModified(_this.path)) {
return true;
}
return ((typeof required === 'function') && !required.apply(this)) ||
_this.checkRequired(v, this);
};
this.originalRequiredValue = required;
if (typeof required === 'string') {
message = required;
required = undefined;
}
...function SchemaString(key, options) {
this.enumValues = [];
this.regExp = null;
SchemaType.call(this, key, options, 'String');
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...enum = function () {
if (this.enumValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.enumValidator;
}, this);
this.enumValidator = false;
}
if (arguments[0] === void 0 || arguments[0] === false) {
return this;
}
var values;
var errorMessage;
if (utils.isObject(arguments[0])) {
values = arguments[0].values;
errorMessage = arguments[0].message;
} else {
values = arguments;
errorMessage = MongooseError.messages.String.enum;
}
for (var i = 0; i < values.length; i++) {
if (undefined !== values[i]) {
this.enumValues.push(this.cast(values[i]));
}
}
var vals = this.enumValues;
this.enumValidator = function(v) {
return undefined === v || ~vals.indexOf(v);
};
this.validators.push({
validator: this.enumValidator,
message: errorMessage,
type: 'enum',
enumValues: vals
});
return this;
}n/a
lowercase = function (shouldApply) {
if (arguments.length > 0 && !shouldApply) {
return this;
}
return this.set(function(v, self) {
if (typeof v !== 'string') {
v = self.cast(v);
}
if (v) {
return v.toLowerCase();
}
return v;
});
}n/a
function match(regExp, message) {
// yes, we allow multiple match validators
var msg = message || MongooseError.messages.String.match;
var matchValidator = function(v) {
if (!regExp) {
return false;
}
var ret = ((v != null && v !== '')
? regExp.test(v)
: true);
return ret;
};
this.validators.push({
validator: matchValidator,
message: msg,
type: 'regexp',
regexp: regExp
});
return this;
}...
*/
/**
* Appends a new custom $match operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.match({ department: { $in: [ "sales", "engineering"
; ] } });
*
* @see $match http://docs.mongodb.org/manual/reference/aggregation/match/
* @method match
* @memberOf Aggregate
* @param {Object} arg $match operator contents
* @return {Aggregate}
* @api public
...maxlength = function (value, message) {
if (this.maxlengthValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.maxlengthValidator;
}, this);
}
if (value !== null && value !== undefined) {
var msg = message || MongooseError.messages.String.maxlength;
msg = msg.replace(/{MAXLENGTH}/, value);
this.validators.push({
validator: this.maxlengthValidator = function(v) {
return v === null || v.length <= value;
},
message: msg,
type: 'maxlength',
maxlength: value
});
}
return this;
}n/a
minlength = function (value, message) {
if (this.minlengthValidator) {
this.validators = this.validators.filter(function(v) {
return v.validator !== this.minlengthValidator;
}, this);
}
if (value !== null && value !== undefined) {
var msg = message || MongooseError.messages.String.minlength;
msg = msg.replace(/{MINLENGTH}/, value);
this.validators.push({
validator: this.minlengthValidator = function(v) {
return v === null || v.length >= value;
},
message: msg,
type: 'minlength',
minlength: value
});
}
return this;
}n/a
trim = function (shouldTrim) {
if (arguments.length > 0 && !shouldTrim) {
return this;
}
return this.set(function(v, self) {
if (typeof v !== 'string') {
v = self.cast(v);
}
if (v) {
return v.trim();
}
return v;
});
}...
// add custom jade filters
require('./docs/helpers/filters')(jade);
function getVersion() {
var hist = fs.readFileSync('./History.md', 'utf8').replace(/\r/g, '\n').split('\n');
for (var i = 0; i < hist.length; ++i) {
var line = (hist[i] || '').trim();
if (!line) {
continue;
}
var match = /^\s*([^\s]+)\s/.exec(line);
if (match && match[1]) {
return match[1];
}
...uppercase = function (shouldApply) {
if (arguments.length > 0 && !shouldApply) {
return this;
}
return this.set(function(v, self) {
if (typeof v !== 'string') {
v = self.cast(v);
}
if (v) {
return v.toUpperCase();
}
return v;
});
}n/a
function Subdocument(value, fields) {
this.$isSingleNested = true;
Document.call(this, value, fields);
}n/a
invalidate = function (path, err, val) {
Document.prototype.invalidate.call(this, path, err, val);
if (this.$parent) {
this.$parent.invalidate([this.$basePath, path].join('.'), err, val);
} else if (err.kind === 'cast' || err.name === 'CastError') {
throw err;
}
}...
if (obj[i] === null) {
doc[i] = null;
} else if (obj[i] !== undefined) {
if (schema) {
try {
doc[i] = schema.cast(obj[i], self, true);
} catch (e) {
self.invalidate(e.path, new ValidatorError({
path: e.path,
message: e.message,
type: 'cast',
value: e.value
}));
}
} else {
...markModified = function (path) {
Document.prototype.markModified.call(this, path);
if (this.$parent) {
if (this.$parent.isDirectModified(this.$basePath)) {
return;
}
this.$parent.markModified([this.$basePath, path].join('.'));
}
}...
if (!merge) {
this.setValue(path, null);
cleanModifiedSubpaths(this, path);
}
if (Object.keys(val).length === 0) {
this.setValue(path, {});
this.markModified(path);
cleanModifiedSubpaths(this, path);
} else {
this.set(val, path, constructing);
}
return this;
}
this.invalidate(path, new MongooseError.CastError('Object', val, path));
...ownerDocument = function () {
if (this.$__.ownerDocument) {
return this.$__.ownerDocument;
}
var parent = this.$parent;
if (!parent) {
return this;
}
while (parent.$parent || parent.__parent) {
parent = parent.$parent || parent.__parent;
}
this.$__.ownerDocument = parent;
return this.$__.ownerDocument;
}...
// the correct model name, treat it as populated
var didPopulate = false;
if (schema.options &&
schema.options.ref &&
val instanceof Document &&
(schema.options.ref === val.constructor.modelName || schema.options.ref === val.constructor.baseModelName)) {
if (this.ownerDocument) {
this.ownerDocument().populated(this.$__fullPath(path),
val._id, {model: val.constructor});
} else {
this.populated(path, val._id, {model: val.constructor});
}
didPopulate = true;
}
...populate = function () {
throw new Error('Mongoose does not support calling populate() on nested ' +
'docs. Instead of `doc.nested.populate("path")`, use ' +
'`doc.populate("nested.path")`');
}...
* Populates document references, executing the `callback` when complete.
* If you want to use promises instead, use this function with
* [`execPopulate()`](#document_Document-execPopulate)
*
* ####Example:
*
* doc
* .populate('company')
* .populate({
* path: 'notes',
* match: /airline/,
* select: 'text',
* model: 'modelName'
* options: opts
* }, function (err, user) {
...remove = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
// If removing entire doc, no need to remove subdoc
if (!options || !options.noop) {
this.$parent.set(this.$basePath, null);
registerRemoveListener(this);
}
if (typeof callback === 'function') {
callback(null);
}
}...
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```
...save = function (fn) {
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve) {
fn && fn();
resolve();
});
}...
Then Mongoose will create the model for your __tickets__ collection, not your __ticket__ collection.
Once we have our model, we can then instantiate it, and save it:
```js
var instance = new MyModel();
instance.my.key = 'hello';
instance.save(function (err) {
//
});
```
Or we can find documents from the same collection
```js
...toBSON = function () {
return this.toObject({
transform: false,
virtuals: false,
_skipDepopulateTopLevel: true,
depopulate: true,
flattenDecimals: false
});
}n/a
function PopulateOptions(path, select, match, options, model, subPopulate) {
this.path = path;
this.match = match;
this.select = select;
this.options = options;
this.model = model;
if (typeof subPopulate === 'object') {
this.populate = subPopulate;
}
this._docs = {};
}n/a
args = function (args, slice, sliceEnd) {
var ret = [];
var len = args.length;
if (0 === len) return ret;
var start = slice < 0
? Math.max(0, slice + len)
: slice || 0;
if (sliceEnd !== undefined) {
len = sliceEnd < 0
? sliceEnd + len
: sliceEnd
}
while (len-- > start) {
ret[len - start] = args[len];
}
return ret;
}...
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.append = function() {
var args = (arguments.length === 1 && util.isArray(arguments[0]))
? arguments[0]
: utils.args(arguments);
if (!args.every(isOperator)) {
throw new Error('Arguments must be aggregate pipeline operators');
}
this._pipeline = this._pipeline.concat(args);
...function clone(obj, options) {
if (obj === undefined || obj === null) {
return obj;
}
if (Array.isArray(obj)) {
return cloneArray(obj, options);
}
if (isMongooseObject(obj)) {
if (options && options.json && typeof obj.toJSON === 'function') {
return obj.toJSON(options);
}
return obj.toObject(options);
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
if (obj instanceof ObjectId) {
return new ObjectId(obj.id);
}
if (obj instanceof Decimal) {
if (options && options.flattenDecimals) {
return obj.toJSON();
}
return Decimal.fromString(obj.toString());
}
if (!obj.constructor && exports.isObject(obj)) {
// object created with Object.create(null)
return cloneObject(obj, options);
}
if (obj.valueOf) {
return obj.valueOf();
}
}...
Aggregate.prototype.exec = function(callback) {
if (!this._model) {
throw new Error('Aggregate not bound to any Model');
}
var _this = this;
var Promise = PromiseProvider.get();
var options = utils.clone(this.options);
if (options && options.cursor) {
if (options.cursor.async) {
delete options.cursor.async;
return new Promise.ES6(function(resolve) {
if (!_this._model.collection.buffer) {
process.nextTick(function() {
...decorate = function (destination, source) {
for (var key in source) {
destination[key] = source[key];
}
}n/a
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) ||
(a instanceof Decimal && b instanceof Decimal)) {
return a.toString() === b.toString();
}
if (a instanceof RegExp && b instanceof RegExp) {
return a.source === b.source &&
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline &&
a.global === b.global;
}
if (typeof a !== 'object' && typeof b !== 'object') {
return a == b;
}
if (a === null || b === null || a === undefined || b === undefined) {
return false;
}
if (a.prototype !== b.prototype) {
return false;
}
// Handle MongooseNumbers
if (a instanceof Number && b instanceof Number) {
return a.valueOf() === b.valueOf();
}
if (Buffer.isBuffer(a)) {
return exports.buffer.areEqual(a, b);
}
if (isMongooseObject(a)) {
a = a.toObject();
}
if (isMongooseObject(b)) {
b = b.toObject();
}
try {
var ka = Object.keys(a),
kb = Object.keys(b),
key, i;
} catch (e) {
// happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length !== kb.length) {
return false;
}
// the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
// ~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] !== kb[i]) {
return false;
}
}
// equivalent values for every corresponding key, and
// ~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}n/a
each = function (arr, fn) {
for (var i = 0; i < arr.length; ++i) {
fn(arr[i]);
}
}...
* Sets the cursor option option for the aggregation query (ignored for < 2.6.0).
* Note the different syntax below: .exec() returns a cursor object, and no callback
* is necessary.
*
* ####Example:
*
* var cursor = Model.aggregate(..).cursor({ batchSize: 1000 }).exec();
* cursor.each(function(error, doc) {
* // use doc
* });
*
* @param {Object} options set the cursor batch size
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.0/api/AggregationCursor.html
*/
...function expires(object) {
if (!(object && object.constructor.name === 'Object')) {
return;
}
if (!('expires' in object)) {
return;
}
var when;
if (typeof object.expires !== 'string') {
when = object.expires;
} else {
when = Math.round(ms(object.expires) / 1000);
}
object.expireAfterSeconds = when;
delete object.expires;
}...
* @api public
*/
Schema.prototype.index = function(fields, options) {
options || (options = {});
if (options.expires) {
utils.expires(options);
}
this._indexes.push([fields, options]);
return this;
};
/**
...getFunctionName = function (fn) {
if (fn.name) {
return fn.name;
}
return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1];
}...
var keys;
var ki;
var _this = this;
// determine if this doc is a result of a query with
// excluded fields
if (fields && utils.getFunctionName(fields.constructor) === 'Object
x27;) {
keys = Object.keys(fields);
ki = keys.length;
if (ki === 1 && keys[0] === '_id') {
exclude = !!fields[keys[ki]];
} else {
while (ki--) {
...getValue = function (path, obj, map) {
return mpath.get(path, obj, '_doc', map);
}...
// If doc._id is not null or undefined
if (doc._id !== null && doc._id !== undefined &&
opts && opts.populated && opts.populated.length) {
var id = String(doc._id);
for (var i = 0; i < opts.populated.length; ++i) {
var item = opts.populated[i];
if (item.isVirtual) {
this.populated(item.path, utils.getValue(item.path, doc), item);
} else {
this.populated(item.path, item._docs[id], item);
}
}
}
init(this, doc, this._doc);
...isMongooseObject = function (v) {
Document || (Document = require('./document'));
MongooseArray || (MongooseArray = require('./types').Array);
MongooseBuffer || (MongooseBuffer = require('./types').Buffer);
return v instanceof Document ||
(v && v.isMongooseArray) ||
(v && v.isMongooseBuffer);
}...
Array.isArray(value.$geometry.coordinates)) {
if (value.$maxDistance != null) {
value.$maxDistance = numbertype.castForQuery(value.$maxDistance);
}
if (value.$minDistance != null) {
value.$minDistance = numbertype.castForQuery(value.$minDistance);
}
if (utils.isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({
transform: false,
virtuals: false
});
}
value = value.$geometry.coordinates;
} else if (geo === '$geoWithin') {
...isNullOrUndefined = function (val) {
return val === null || val === undefined;
}...
* @api private
*/
exports.toObject = function toObject(obj) {
Document || (Document = require('./document'));
var ret;
if (exports.isNullOrUndefined(obj)) {
return obj;
}
if (obj instanceof Document) {
return obj.toObject();
}
...isObject = function (arg) {
if (Buffer.isBuffer(arg)) {
return true;
}
return toString.call(arg) === '[object Object]';
}...
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.graphLookup = function(options) {
var cloneOptions = {};
if (options) {
if (!utils.isObject(options)) {
throw new TypeError('Invalid graphLookup() argument. Must be an object.');
}
utils.mergeClone(cloneOptions, options);
var startWith = cloneOptions.startWith;
if (startWith && typeof startWith === 'string') {
...function merge(to, from, options) {
options = options || {};
var keys = Object.keys(from);
var i = 0;
var len = keys.length;
var key;
if (options.retainKeyOrder) {
while (i < len) {
key = keys[i++];
if (to[key] == null) {
to[key] = from[key];
} else if (exports.isObject(from[key])) {
merge(to[key], from[key], options);
} else if (options.overwrite) {
to[key] = from[key];
}
}
} else {
while (len--) {
key = keys[len];
if (to[key] == null) {
to[key] = from[key];
} else if (exports.isObject(from[key])) {
merge(to[key], from[key], options);
} else if (options.overwrite) {
to[key] = from[key];
}
}
}
}...
};
if (isVirtual && virtual.options && virtual.options.options) {
currentOptions.options = utils.clone(virtual.options.options, {
retainKeyOrder: true
});
}
utils.merge(currentOptions, options);
if (schema && !discriminatorKey) {
currentOptions.model = Model;
}
options.model = Model;
available[modelName] = {
Model: Model,
...mergeClone = function (to, fromObj) {
var keys = Object.keys(fromObj);
var len = keys.length;
var i = 0;
var key;
while (i < len) {
key = keys[i++];
if (typeof to[key] === 'undefined') {
// make sure to retain key order here because of a bug handling the $each
// operator in mongodb 2.4.4
to[key] = exports.clone(fromObj[key], {retainKeyOrder: 1});
} else {
if (exports.isObject(fromObj[key])) {
var obj = fromObj[key];
if (isMongooseObject(fromObj[key]) && !fromObj[key].isMongooseBuffer) {
obj = obj.toObject({ transform: false, virtuals: false });
}
if (fromObj[key].isMongooseBuffer) {
obj = new Buffer(obj);
}
exports.mergeClone(to[key], obj);
} else {
// make sure to retain key order here because of a bug handling the
// $each operator in mongodb 2.4.4
to[key] = exports.clone(fromObj[key], {retainKeyOrder: 1});
}
}
}
}...
Aggregate.prototype.graphLookup = function(options) {
var cloneOptions = {};
if (options) {
if (!utils.isObject(options)) {
throw new TypeError('Invalid graphLookup() argument. Must be an object.');
}
utils.mergeClone(cloneOptions, options);
var startWith = cloneOptions.startWith;
if (startWith && typeof startWith === 'string') {
cloneOptions.startWith = cloneOptions.startWith.charAt(0) === '$' ?
cloneOptions.startWith :
'$' + cloneOptions.startWith;
}
...options = function (defaults, options) {
var keys = Object.keys(defaults),
i = keys.length,
k;
options = options || {};
while (i--) {
k = keys[i];
if (!(k in options)) {
options[k] = defaults[k];
}
}
return options;
}...
}
if (options && options.safe && options.safe.w === 0) {
// if you turn off safe writes, then versioning goes off as well
options.versionKey = false;
}
options = utils.options({
strict: true,
bufferCommands: true,
capped: false, // { size, max, autoIndexId }
versionKey: '__v',
discriminatorKey: '__t',
minimize: true,
autoIndex: null,
...function populate(path, select, model, match, options, subPopulate) {
// The order of select/conditions args is opposite Model.find but
// necessary to keep backward compatibility (select could be
// an array, string, or object literal).
// might have passed an object specifying all arguments
if (arguments.length === 1) {
if (path instanceof PopulateOptions) {
return [path];
}
if (Array.isArray(path)) {
return path.map(function(o) {
return exports.populate(o)[0];
});
}
if (exports.isObject(path)) {
match = path.match;
options = path.options;
select = path.select;
model = path.model;
subPopulate = path.populate;
path = path.path;
}
} else if (typeof model !== 'string' && typeof model !== 'function') {
options = match;
match = model;
model = undefined;
}
if (typeof path !== 'string') {
throw new TypeError('utils.populate: invalid path. Expected string. Got typeof `' + typeof path + '`');
}
if (typeof subPopulate === 'object') {
subPopulate = exports.populate(subPopulate);
}
var ret = [];
var paths = path.split(' ');
options = exports.clone(options, { retainKeyOrder: true });
for (var i = 0; i < paths.length; ++i) {
ret.push(new PopulateOptions(paths[i], select, match, options, model, subPopulate));
}
return ret;
}...
* Populates document references, executing the `callback` when complete.
* If you want to use promises instead, use this function with
* [`execPopulate()`](#document_Document-execPopulate)
*
* ####Example:
*
* doc
* .populate('company')
* .populate({
* path: 'notes',
* match: /airline/,
* select: 'text',
* model: 'modelName'
* options: opts
* }, function (err, user) {
...random = function () {
return Math.random().toString().substr(3);
}...
/*!
* Generates a random string
*
* @api private
*/
exports.random = function() {
return Math.random().toString().substr(3);
};
/*!
* Merges `from` into `to` without overwriting existing properties.
*
* @param {Object} to
* @param {Object} from
...setValue = function (path, val, obj, map) {
mpath.set(path, val, obj, '_doc', map);
}...
}
var pathType = this.schema.pathType(path);
if (pathType === 'nested' && val) {
if (utils.isObject(val) &&
(!val.constructor || utils.getFunctionName(val.constructor) === 'Object')) {
if (!merge) {
this.setValue(path, null);
cleanModifiedSubpaths(this, path);
}
if (Object.keys(val).length === 0) {
this.setValue(path, {});
this.markModified(path);
cleanModifiedSubpaths(this, path);
...function tick(callback) {
if (typeof callback !== 'function') {
return;
}
return function() {
try {
callback.apply(this, arguments);
} catch (err) {
// only nextTick on err to get out of
// the event loop and avoid state corruption.
process.nextTick(function() {
throw err;
});
}
};
}...
var indexFields = index[0];
var options = index[1];
_handleSafe(options);
indexSingleStart(indexFields, options);
model.collection.ensureIndex(indexFields, options, utils.tick(function(err, name) {
indexSingleDone(err, indexFields, options, name);
if (err) {
return done(err);
}
create();
}));
};
...toCollectionName = function (name, options) {
options = options || {};
if (name === 'system.profile') {
return name;
}
if (name === 'system.indexes') {
return name;
}
if (options.pluralization === false) {
return name;
}
return pluralize(name.toLowerCase());
}...
? schema
: _this.prototype.schema;
var options = s.options || {};
if (!collection) {
collection = _this.prototype.schema.get('collection')
|| utils.toCollectionName(_this.modelName, options);
}
var collectionOptions = {
bufferCommands: s ? options.bufferCommands : true,
capped: s && options.capped
};
...function toObject(obj) {
Document || (Document = require('./document'));
var ret;
if (exports.isNullOrUndefined(obj)) {
return obj;
}
if (obj instanceof Document) {
return obj.toObject();
}
if (Array.isArray(obj)) {
ret = [];
for (var i = 0, len = obj.length; i < len; ++i) {
ret.push(toObject(obj[i]));
}
return ret;
}
if ((obj.constructor && exports.getFunctionName(obj.constructor) === 'Object') ||
(!obj.constructor && exports.isObject(obj))) {
ret = {};
for (var k in obj) {
ret[k] = toObject(obj[k]);
}
return ret;
}
return obj;
}...
if (value.$maxDistance != null) {
value.$maxDistance = numbertype.castForQuery(value.$maxDistance);
}
if (value.$minDistance != null) {
value.$minDistance = numbertype.castForQuery(value.$minDistance);
}
if (utils.isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({
transform: false,
virtuals: false
});
}
value = value.$geometry.coordinates;
} else if (geo === '$geoWithin') {
if (value.$geometry) {
...function ValidationError(instance) {
this.errors = {};
if (instance && instance.constructor.name === 'model') {
MongooseError.call(this, instance.constructor.modelName + ' validation failed');
} else {
MongooseError.call(this, 'Validation failed');
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.name = 'ValidationError';
if (instance) {
instance.errors = this.errors;
}
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...toString = function () {
var ret = this.name + ': ';
var msgs = [];
Object.keys(this.errors || {}).forEach(function(key) {
if (this === this.errors[key]) {
return;
}
msgs.push(String(this.errors[key]));
}, this);
return ret + msgs.join(', ');
}...
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments.
To do so, just pass the new values to `next`:
```js
.pre(method, function firstPre (next, methodArg1, methodArg2) {
// Mutate methodArg1
next("altered-" + methodArg1.toString(), methodArg2);
});
// pre declaration is chainable
.pre(method, function secondPre (next, methodArg1, methodArg2) {
console.log(methodArg1);
// => 'altered-originalValOfMethodArg1'
...function ValidatorError(properties) {
var msg = properties.message;
if (!msg) {
msg = MongooseError.messages.general.default;
}
var message = this.formatMessage(msg, properties);
MongooseError.call(this, message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.properties = properties;
this.name = 'ValidatorError';
this.kind = properties.type;
this.path = properties.path;
this.value = properties.value;
this.reason = properties.reason;
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...formatMessage = function (msg, properties) {
var propertyNames = Object.keys(properties);
for (var i = 0; i < propertyNames.length; ++i) {
var propertyName = propertyNames[i];
if (propertyName === 'message') {
continue;
}
msg = msg.replace('{' + propertyName.toUpperCase() + '}', properties[propertyName]);
}
return msg;
}...
function ValidatorError(properties) {
var msg = properties.message;
if (!msg) {
msg = MongooseError.messages.general.default;
}
var message = this.formatMessage(msg, properties);
MongooseError.call(this, message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.properties = properties;
...toString = function () {
return this.message;
}...
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments.
To do so, just pass the new values to `next`:
```js
.pre(method, function firstPre (next, methodArg1, methodArg2) {
// Mutate methodArg1
next("altered-" + methodArg1.toString(), methodArg2);
});
// pre declaration is chainable
.pre(method, function secondPre (next, methodArg1, methodArg2) {
console.log(methodArg1);
// => 'altered-originalValOfMethodArg1'
...function VersionError(doc) {
MongooseError.call(this, 'No matching document found for id "' + doc._id +
'"');
this.name = 'VersionError';
}n/a
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}...
}
if (obj.constructor) {
switch (exports.getFunctionName(obj.constructor)) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
...function VirtualType(options, name) {
this.path = name;
this.getters = [];
this.setters = [];
this.options = options || {};
}n/a
applyGetters = function (value, scope) {
var v = value;
for (var l = this.getters.length - 1; l >= 0; l--) {
v = this.getters[l].call(scope, v, this);
}
return v;
}...
if (adhoc) {
obj = adhoc.cast(obj);
}
// Check if this path is populated - don't apply getters if it is,
// because otherwise its a nested object. See gh-3357
if (schema && !this.populated(path)) {
obj = schema.applyGetters(obj, this);
}
return obj;
};
/**
* Returns the schematype for the given `path`.
...applySetters = function (value, scope) {
var v = value;
for (var l = this.setters.length - 1; l >= 0; l--) {
v = this.setters[l].call(scope, v, this);
}
return v;
}...
if (strict === 'throw') {
throw new StrictModeError(path);
}
return this;
}
} else if (pathType === 'virtual') {
schema = this.schema.virtualpath(path);
schema.applySetters(val, this);
return this;
} else {
schema = this.$__path(path);
}
var pathToMark;
...get = function (fn) {
this.getters.push(fn);
return this;
}...
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
...set = function (fn) {
this.setters.push(fn);
return this;
}...
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
...