- index.js
Storage#createCollection(
name,schema,[api])Create a collection and get it
show codeParameters:
name<string> <ul> <li>collection name</li> </ul>schema<storage.Schema>[api]<Object> <ul> <li>reference to the Api-client resource instance</li> </ul>
Storage.prototype.createCollection = function( name, schema, api ){ if ( this[ name ] ){ console.info('storage::collection: `' + name + '` already exist'); return this[ name ]; } if ( name == null ){ throw new TypeError('storage.createCollection( name, schema ) - `name` must be exist, `schema` must be Schema instance'); } if ( schema == null || 'Schema' !== utils.getFunctionName( schema.constructor ) ){ throw new TypeError('storage.createCollection( name, schema ) - `schema` must be Schema instance'); } this.collectionNames.push( name ); this[ name ] = new Collection( name, schema, api ); return this[ name ]; };Storage#getCollectionNames()
To obtain the names of the collections in an array
show codeStorage.prototype.getCollectionNames = function(){ return this.collectionNames; };Storage#Schema()
The Storage Schema constructor
Example:
var Schema = storage.Schema; var CatSchema = new Schema(..);Storage()
Storage constructor.
show codeThe exports object of the
storagemodule is an instance of this class.
Most apps will only use this one instance.function Storage () { this.collectionNames = []; }Storage#Storage()
The Storage constructor
The exports of the storage module is an instance of this class.
Example:
var storage2 = new storage.Storage();Storage#SchemaTypes
The various Storage SchemaTypes.
Note:
Alias of storage.Schema.Types for backwards compatibility.
show codeStorage.prototype.SchemaTypes = Schema.Types;Storage#Types
The various Storage Types.
Example:
var array = storage.Types.Array;Types:
Using this exposed access to the
ObjectIdtype, we can construct ids on demand.show codevar ObjectId = storage.Types.ObjectId; var id1 = new ObjectId;Storage.prototype.Types = Types; - binary.js
Binary(
buffer,[subType])A class representation of the BSON Binary type.
Parameters:
Returns:
- <Grid>
Sub types
- BSON.BSON_BINARY_SUBTYPE_DEFAULT, default BSON type.
- BSON.BSON_BINARY_SUBTYPE_FUNCTION, BSON function type.
- BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY, BSON byte array type.
- BSON.BSON_BINARY_SUBTYPE_UUID, BSON uuid type.
- BSON.BSON_BINARY_SUBTYPE_MD5, BSON md5 type.
- BSON.BSON_BINARY_SUBTYPE_USER_DEFINED, BSON user defined type.
convertArraytoUtf8BinaryString()
Convert Array ot Uint8Array to Binary String
show codevar convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { var result = ''; for(var i = startIndex; i < endIndex; i++) { result = result + String.fromCharCode(byteArray[i]); } return result; }; Binary.BUFFER_SIZE = 256;Binary#length()
Length.
show codeReturns:
- <Number> <p>the length of the binary.</p>
Binary.prototype.length = function length() { return this.position; };Binary#put(
byte_value)Updates this binary with byte_value.
show codeParameters:
byte_value<Character> <p>a single byte we wish to write.</p>
Binary.prototype.put = function put(byte_value) { // If it's a string and a has more than one character throw an error if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array"); if(typeof byte_value != 'number' && byte_value < 0 || byte_value > 255) throw new Error("only accepts number in a valid unsigned byte range 0-255"); // Decode the byte value once var decoded_byte = null; if(typeof byte_value === 'string') { decoded_byte = byte_value.charCodeAt(0); } else if(byte_value['length'] != null) { decoded_byte = byte_value[0]; } else { decoded_byte = byte_value; } if(this.buffer.length > this.position) { this.buffer[this.position++] = decoded_byte; } else { if(typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer)) { // Create additional overflow buffer var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length); // Combine the two buffers together this.buffer.copy(buffer, 0, 0, this.buffer.length); this.buffer = buffer; this.buffer[this.position++] = decoded_byte; } else { var buffer = null; // Create a new buffer (typed or normal array) if(Object.prototype.toString.call(this.buffer) === '[object Uint8Array]') { buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length)); } else { buffer = new Array(Binary.BUFFER_SIZE + this.buffer.length); } // We need to copy all the content to the new array for(var i = 0; i < this.buffer.length; i++) { buffer[i] = this.buffer[i]; } // Reassign the buffer this.buffer = buffer; // Write the byte this.buffer[this.position++] = decoded_byte; } } };Binary#read(
position,length)Reads length bytes starting at position.
Parameters:
show codeReturns:
- <Buffer>
Binary.prototype.read = function read(position, length) { length = length && length > 0 ? length : this.position; // Let's return the data based on the type we have if(this.buffer['slice']) { return this.buffer.slice(position, position + length); } else { // Create a buffer to keep the result var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length); for(var i = 0; i < length; i++) { buffer[i] = this.buffer[position++]; } } // Return the buffer return buffer; };Binary#toJSON()
show codeBinary.prototype.toJSON = function() { return this.buffer != null ? this.buffer.toString('base64') : ''; };Binary#toString()
show codeBinary.prototype.toString = function(format) { return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : ''; }; // Binary default subtype var BSON_BINARY_SUBTYPE_DEFAULT = 0;Binary#value()
Returns the value of this binary as a string.
show codeReturns:
- <String>
Binary.prototype.value = function value(asRaw) { asRaw = asRaw == null ? false : asRaw; // Optimize to serialize for the situation where the data == size of buffer if(asRaw && typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer) && this.buffer.length == this.position) return this.buffer; // If it's a node.js buffer object if(typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer)) { return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position); } else { if(asRaw) { // we support the slice command use it if(this.buffer['slice'] != null) { return this.buffer.slice(0, this.position); } else { // Create a new buffer to copy content to var newBuffer = Object.prototype.toString.call(this.buffer) === '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position); // Copy content for(var i = 0; i < this.position; i++) { newBuffer[i] = this.buffer[i]; } // Return the buffer return newBuffer; } } else { return convertArraytoUtf8BinaryString(this.buffer, 0, this.position); } } };Binary#write(
string,offset)Writes a buffer or string to the binary.
show codeParameters:
Binary.prototype.write = function write(string, offset) { offset = typeof offset === 'number' ? offset : this.position; // If the buffer is to small let's extend the buffer if(this.buffer.length < offset + string.length) { var buffer = null; // If we are in node.js if(typeof Buffer !== 'undefined' && Buffer.isBuffer(this.buffer)) { buffer = new Buffer(this.buffer.length + string.length); this.buffer.copy(buffer, 0, 0, this.buffer.length); } else if(Object.prototype.toString.call(this.buffer) === '[object Uint8Array]') { // Create a new buffer buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length)) // Copy the content for(var i = 0; i < this.position; i++) { buffer[i] = this.buffer[i]; } } // Assign the new buffer this.buffer = buffer; } if(typeof Buffer !== 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) { string.copy(this.buffer, offset, 0, string.length); this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; // offset = string.length } else if(typeof Buffer !== 'undefined' && typeof string === 'string' && Buffer.isBuffer(this.buffer)) { this.buffer.write(string, 'binary', offset); this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; // offset = string.length; } else if(Object.prototype.toString.call(string) === '[object Uint8Array]' || Object.prototype.toString.call(string) === '[object Array]' && typeof string !== 'string') { for(var i = 0; i < string.length; i++) { this.buffer[offset++] = string[i]; } this.position = offset > this.position ? offset : this.position; } else if(typeof string === 'string') { for(var i = 0; i < string.length; i++) { this.buffer[offset++] = string.charCodeAt(i); } this.position = offset > this.position ? offset : this.position; } };writeStringToArray()
show codevar writeStringToArray = function(data) { // Create a buffer var buffer = typeof Uint8Array !== 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length); // Write the content to the buffer for(var i = 0; i < data.length; i++) { buffer[i] = data.charCodeAt(i); } // Write the string to the buffer return buffer; }; - deferred.js
MISSING method name
Standalone Deferred
Copyright 2012 Otto Vehviläinen
Released under MIT license
https://github.com/Mumakil/Standalone-Deferredshow codeThis is a standalone implementation of the wonderful jQuery.Deferred API.
The documentation here is only for quick reference, for complete api please
see the great work of the original project:var Promise, flatten, isObservable, __slice = Array.prototype.slice, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; if (!Array.prototype.forEach) throw new Error('Deferred requires Array.forEach');MISSING method name
Tells if an object is observable
show codeisObservable = function(obj) { return (obj instanceof Deferred) || (obj instanceof Promise); };MISSING method name
Flatten a two dimensional array into one dimension.
show code
Removes elements that are not functionsflatten = function(args) { var flatted; if (!args) return []; flatted = []; args.forEach(function(item) { if (item) { if (typeof item === 'function') { return flatted.push(item); } else { return args.forEach(function(fn) { if (typeof fn === 'function') return flatted.push(fn); }); } } }); return flatted; };MISSING method name
Promise object functions as a proxy for a Deferred, except
show code
it does not let you modify the state of the DeferredPromise = (function() { Promise.prototype._deferred = null; function Promise(deferred) { this._deferred = deferred; } Promise.prototype.always = function() { var args, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; (_ref = this._deferred).always.apply(_ref, args); return this; }; Promise.prototype.done = function() { var args, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; (_ref = this._deferred).done.apply(_ref, args); return this; }; Promise.prototype.fail = function() { var args, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; (_ref = this._deferred).fail.apply(_ref, args); return this; }; Promise.prototype.pipe = function(doneFilter, failFilter) { return this._deferred.pipe(doneFilter, failFilter); }; Promise.prototype.state = function() { return this._deferred.state(); }; Promise.prototype.then = function(done, fail) { this._deferred.then(done, fail); return this; }; return Promise; })();Deferred()
Initializes a new Deferred. You can pass a function as a parameter
show code
to be executed immediately after init. The function receives
the new deferred object as a parameter and this is also set to the
same object.function Deferred(fn) { this.then = __bind(this.then, this); this.resolveWith = __bind(this.resolveWith, this); this.resolve = __bind(this.resolve, this); this.rejectWith = __bind(this.rejectWith, this); this.reject = __bind(this.reject, this); this.promise = __bind(this.promise, this); this.progress = __bind(this.progress, this); this.pipe = __bind(this.pipe, this); this.notifyWith = __bind(this.notifyWith, this); this.notify = __bind(this.notify, this); this.fail = __bind(this.fail, this); this.done = __bind(this.done, this); this.always = __bind(this.always, this); if (typeof fn === 'function') fn.call(this, this); this._state = 'pending'; }Deferred#always()
Pass in functions or arrays of functions to be executed when the
show code
Deferred object changes state from pending. If the state is already
rejected or resolved, the functions are executed immediately. They
receive the arguments that are passed to reject or resolve and this
is set to the object defined by rejectWith or resolveWith if those
variants are used.Deferred.prototype.always = function() { var args, functions, _ref, _this = this; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 0) return this; functions = flatten(args); if (this._state === 'pending') { this._alwaysCallbacks || (this._alwaysCallbacks = []); (_ref = this._alwaysCallbacks).push.apply(_ref, functions); } else { functions.forEach(function(fn) { return fn.apply(_this._context, _this._withArguments); }); } return this; };Deferred#done()
Pass in functions or arrays of functions to be executed when the
show code
Deferred object is resolved. If the object has already been resolved,
the functions are executed immediately. If the object has been rejected,
nothing happens. The functions receive the arguments that are passed
to resolve and this is set to the object defined by resolveWith if that
variant is used.Deferred.prototype.done = function() { var args, functions, _ref, _this = this; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 0) return this; functions = flatten(args); if (this._state === 'resolved') { functions.forEach(function(fn) { return fn.apply(_this._context, _this._withArguments); }); } else if (this._state === 'pending') { this._doneCallbacks || (this._doneCallbacks = []); (_ref = this._doneCallbacks).push.apply(_ref, functions); } return this; };Deferred#fail()
Pass in functions or arrays of functions to be executed when the
show code
Deferred object is rejected. If the object has already been rejected,
the functions are executed immediately. If the object has been resolved,
nothing happens. The functions receive the arguments that are passed
to reject and this is set to the object defined by rejectWith if that
variant is used.Deferred.prototype.fail = function() { var args, functions, _ref, _this = this; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 0) return this; functions = flatten(args); if (this._state === 'rejected') { functions.forEach(function(fn) { return fn.apply(_this._context, _this._withArguments); }); } else if (this._state === 'pending') { this._failCallbacks || (this._failCallbacks = []); (_ref = this._failCallbacks).push.apply(_ref, functions); } return this; };Deferred#notify()
Notify progress callbacks. The callbacks get passed the arguments given to notify.
show code
If the object has resolved or rejected, nothing will happenDeferred.prototype.notify = function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; this.notifyWith.apply(this, [window].concat(__slice.call(args))); return this; };Deferred#notifyWith()
Notify progress callbacks with additional context. Works the same way as notify(),
show code
except this is set to context when calling the functions.Deferred.prototype.notifyWith = function() { var args, context, _ref; context = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; if (this._state !== 'pending') return this; if ((_ref = this._progressCallbacks) != null) { _ref.forEach(function(fn) { return fn.apply(context, args); }); } return this; };Deferred#pipe()
Returns a new Promise object that's tied to the current Deferred. The doneFilter
show code
and failFilter can be used to modify the final values that are passed to the
callbacks of the new promise. If the parameters passed are falsy, the promise
object resolves or rejects normally. If the filter functions return a value,
that one is passed to the respective callbacks. The filters can also return a
new Promise or Deferred object, of which rejected / resolved will control how the
callbacks fire.Deferred.prototype.pipe = function(doneFilter, failFilter) { var def; def = new Deferred(); this.done(function() { var args, result, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (doneFilter != null) { result = doneFilter.apply(this, args); if (isObservable(result)) { return result.done(function() { var doneArgs, _ref; doneArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return (_ref = def.resolveWith).call.apply(_ref, [def, this].concat(__slice.call(doneArgs))); }).fail(function() { var failArgs, _ref; failArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return (_ref = def.rejectWith).call.apply(_ref, [def, this].concat(__slice.call(failArgs))); }); } else { return def.resolveWith.call(def, this, result); } } else { return (_ref = def.resolveWith).call.apply(_ref, [def, this].concat(__slice.call(args))); } }); this.fail(function() { var args, result, _ref, _ref2; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (failFilter != null) { result = failFilter.apply(this, args); if (isObservable(result)) { result.done(function() { var doneArgs, _ref; doneArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return (_ref = def.resolveWith).call.apply(_ref, [def, this].concat(__slice.call(doneArgs))); }).fail(function() { var failArgs, _ref; failArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return (_ref = def.rejectWith).call.apply(_ref, [def, this].concat(__slice.call(failArgs))); }); } else { def.rejectWith.call(def, this, result); } return (_ref = def.rejectWith).call.apply(_ref, [def, this].concat(__slice.call(args))); } else { return (_ref2 = def.rejectWith).call.apply(_ref2, [def, this].concat(__slice.call(args))); } }); return def.promise(); };Deferred#progress()
Add progress callbacks to be fired when using notify()
show codeDeferred.prototype.progress = function() { var args, functions, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 0 || this._state !== 'pending') return this; functions = flatten(args); this._progressCallbacks || (this._progressCallbacks = []); (_ref = this._progressCallbacks).push.apply(_ref, functions); return this; };Deferred#promise()
Returns the promise object of this Deferred.
show codeDeferred.prototype.promise = function() { return this._promise || (this._promise = new Promise(this)); };Deferred#reject()
Reject this Deferred. If the object has already been rejected or resolved,
show code
nothing happens. Parameters passed to reject will be handed to all current
and future fail and always callbacks.Deferred.prototype.reject = function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; this.rejectWith.apply(this, [window].concat(__slice.call(args))); return this; };Deferred#rejectWith()
Reject this Deferred with additional context. Works the same way as reject, except
show code
the first parameter is used as this when calling the fail and always callbacks.Deferred.prototype.rejectWith = function() { var args, context, _ref, _ref2, _this = this; context = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; if (this._state !== 'pending') return this; this._state = 'rejected'; this._withArguments = args; this._context = context; if ((_ref = this._failCallbacks) != null) { _ref.forEach(function(fn) { return fn.apply(_this._context, args); }); } if ((_ref2 = this._alwaysCallbacks) != null) { _ref2.forEach(function(fn) { return fn.apply(_this._context, args); }); } return this; };Deferred#resolve()
Resolves this Deferred object. If the object has already been rejected or resolved,
show code
nothing happens. Parameters passed to resolve will be handed to all current and
future done and always callbacks.Deferred.prototype.resolve = function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; this.resolveWith.apply(this, [window].concat(__slice.call(args))); return this; };Deferred#resolveWith()
Resolve this Deferred with additional context. Works the same way as resolve, except
show code
the first parameter is used as this when calling the done and always callbacks.Deferred.prototype.resolveWith = function() { var args, context, _ref, _ref2, _this = this; context = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; if (this._state !== 'pending') return this; this._state = 'resolved'; this._context = context; this._withArguments = args; if ((_ref = this._doneCallbacks) != null) { _ref.forEach(function(fn) { return fn.apply(_this._context, args); }); } if ((_ref2 = this._alwaysCallbacks) != null) { _ref2.forEach(function(fn) { return fn.apply(_this._context, args); }); } return this; };Deferred#state()
Returns the state of this Deferred. Can be 'pending', 'rejected' or 'resolved'.
show codeDeferred.prototype.state = function() { return this._state; };Deferred#then()
Convenience function to specify each done, fail and progress callbacks at the same time.
show codeDeferred.prototype.then = function(doneCallbacks, failCallbacks, progressCallbacks) { this.done(doneCallbacks); this.fail(failCallbacks); this.progress(progressCallbacks); return this; };Deferred.when()
Returns a new promise object which will resolve when all of the deferreds or promises
show code
passed to the function resolve. The callbacks receive all the parameters that the
individual resolves yielded as an array. If any of the deferreds or promises are
rejected, the promise will be rejected immediately.Deferred.when = function() { var allDoneArgs, allReady, args, readyCount; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 0) return new Deferred().resolve().promise(); if (args.length === 1) return args[0].promise(); allReady = new Deferred(); readyCount = 0; allDoneArgs = []; args.forEach(function(dfr, index) { return dfr.done(function() { var doneArgs; doneArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; readyCount += 1; allDoneArgs[index] = doneArgs; if (readyCount === args.length) { return allReady.resolve.apply(allReady, allDoneArgs); } }).fail(function() { var failArgs; failArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return allReady.rejectWith.apply(allReady, [this].concat(__slice.call(failArgs))); }); }); return allReady.promise(); }; module.exports = Deferred; - document.js
Document#$__fullPath(
[path])Returns the full path to this document.
Parameters:
[path]<String>
Returns:
- <String>
Document#$__presaveValidate()
Handle generic save stuff.
to solve #1446 use use hierarchy instead of hooksDocument#$__set()
Handles the actual setting of the value and marking the path modified if appropriate.
Document#$__setSchema(
schema)Assigns/compiles
schemainto this documents prototype.Parameters:
schema<Schema>
Document#$__try(
fn,[scope])Catches errors that occur during execution of
fnand stores them to later be passed whensave()is executed.Parameters:
Document(
data,[collectionName],schema,[fields],[init])Конструктор документа.
Parameters:
data<object> <ul> <li>значения, которые нужно установить</li> </ul>[collectionName]<string> <ul> <li>коллекция в которой будет находится документ</li> </ul>schema<Schema> <ul> <li>схема по которой будет создан документ</li> </ul>[fields]<object> <ul> <li>выбранные поля в документе (не реализовано)</li> </ul>[init]<Boolean> <ul> <li>hydrate document - наполнить документ данными (используется в api-client)</li> </ul>
Document#empty()
Очищает документ (выставляет значение по умолчанию или undefined)
show codeDocument.prototype.empty = function(){ var doc = this , self = this , paths = Object.keys( this.schema.paths ) , plen = paths.length , ii = 0; for ( ; ii < plen; ++ii ) { var p = paths[ii]; if ( '_id' == p ) continue; var type = this.schema.paths[ p ] , path = p.split('.') , len = path.length , last = len - 1 , doc_ = doc , i = 0; for ( ; i < len; ++i ) { var piece = path[ i ] , defaultVal; if ( i === last ) { defaultVal = type.getDefault( self, true ); doc_[ piece ] = defaultVal || undefined; self.$__.activePaths.default( p ); } else { doc_ = doc_[ piece ] || ( doc_[ piece ] = {} ); } } } };Document#equals(
doc)Returns true if the Document stores the same data as doc.
Parameters:
doc<Document> <p>a document to compare</p>
Returns:
- <Boolean>
show codeDocuments are considered equal when they have matching
_ids, unless neither
document has an_id, in which case this function falls back to usingdeepEqual().Document.prototype.equals = function( doc ){ var tid = this.get('_id'); var docid = doc.get('_id'); if (!tid && !docid) { return deepEqual(this, doc); } return tid && tid.equals ? (docid ? tid.equals(docid) : false) : tid === docid; };Document#get(
path,[type])Returns the value of a path.
Parameters:
show codeExample
// path doc.get('age') // 47 // dynamic casting to a string doc.get('age', String) // "47"Document.prototype.get = function (path, type) { var adhocs; if (type) { adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {}); adhocs[path] = Schema.interpretAsType(path, type); } var schema = this.$__path(path) || this.schema.virtualpath(path) , pieces = path.split('.') , obj = this._doc; for (var i = 0, l = pieces.length; i < l; i++) { obj = undefined === obj || null === obj ? undefined : obj[pieces[i]]; } if (schema) { obj = schema.applyGetters(obj, this); } this.adapterHooks.documentGetValue.call( this, this, path ); return obj; };Document#getValue(
path)Gets a raw value from a path (no getters)
show codeParameters:
path<String>
Document.prototype.getValue = function (path) { return utils.getValue(path, this._doc); };Document#init(
data)Initializes the document without setters or marking anything modified.
Parameters:
data<Object> <p>document returned by server</p>
show codeCalled internally after a document is returned from server.
Document.prototype.init = function ( data ) { this.isNew = false; //todo: сдесь всё изменится, смотреть коммент метода this.populated // handle docs with populated pathsDocument#invalidate(
path,errorMsg,value)Marks a path as invalid, causing validation to fail.
Parameters:
show codeThe
errorMsgargument will become the message of theValidationError.The
valueargument (if passed) will be available through theValidationError.valueproperty.doc.invalidate('size', 'must be less than 20', 14); doc.validate(function (err) { console.log(err) // prints { message: 'Validation failed', name: 'ValidationError', errors: { size: { message: 'must be less than 20', name: 'ValidatorError', path: 'size', type: 'user defined', value: 14 } } } })Document.prototype.invalidate = function (path, errorMsg, value) { if (!this.$__.validationError) { this.$__.validationError = new ValidationError(this); } if (this.$__.validationError.errors[path]) return; if (!errorMsg || 'string' === typeof errorMsg) { errorMsg = new ValidatorError({ path: path, message: errorMsg, type: 'user defined', value: value }); } if (this.$__.validationError == errorMsg) return; this.$__.validationError.errors[path] = errorMsg; };Document#isDirectModified(
path)Returns true if
pathwas directly set and modified, else false.Parameters:
path<String>
Returns:
- <Boolean>
show codeExample
doc.set('documents.0.title', 'changed'); doc.isDirectModified('documents.0.title') // true doc.isDirectModified('documents') // falseDocument.prototype.isDirectModified = function (path) { return (path in this.$__.activePaths.states.modify); };Document#isInit(
path)Checks if
pathwas initialized.Parameters:
path<String>
show codeReturns:
- <Boolean>
Document.prototype.isInit = function (path) { return (path in this.$__.activePaths.states.init); };Document#isModified(
[path])Returns true if this document was modified, else false.
Parameters:
[path]<String> <p>optional</p>
Returns:
- <Boolean>
show codeIf
pathis given, checks if a path or any full path containingpathas part of its path chain has been modified.Example
doc.set('documents.0.title', 'changed'); doc.isModified() // true doc.isModified('documents') // true doc.isModified('documents.0.title') // true doc.isDirectModified('documents') // falseDocument.prototype.isModified = function (path) { return path ? !!~this.modifiedPaths().indexOf(path) : this.$__.activePaths.some('modify'); };Document#isSelected(
path)Checks if
pathwas selected in the source query which initialized this document.Parameters:
path<String>
Returns:
- <Boolean>
show codeExample
Thing.findOne().select('name').exec(function (err, doc) { doc.isSelected('name') // true doc.isSelected('age') // false })Document.prototype.isSelected = function isSelected (path) { if (this.$__.selected) { if ('_id' === path) { return 0 !== this.$__.selected._id; } var paths = Object.keys(this.$__.selected) , i = paths.length , inclusive = false , cur; if (1 === i && '_id' === paths[0]) { // only _id was selected. return 0 === this.$__.selected._id; } while (i--) { cur = paths[i]; if ('_id' === cur) continue; inclusive = !! this.$__.selected[cur]; break; } if (path in this.$__.selected) { return inclusive; } i = paths.length; var pathDot = path + '.'; while (i--) { cur = paths[i]; if ('_id' === cur) continue; if (0 === cur.indexOf(pathDot)) { return inclusive; } if (0 === pathDot.indexOf(cur + '.')) { return inclusive; } } return ! inclusive; } return true; };Document#markModified(
path)Marks the path as having pending changes to write to the db.
Parameters:
path<String> <p>the path to mark modified</p>
show codeVery helpful when using Mixed types.
Example:
doc.mixed.type = 'changed'; doc.markModified('mixed.type'); doc.save() // changes to mixed.type are now persistedDocument.prototype.markModified = function (path) { this.$__.activePaths.modify(path); };Document#modifiedPaths()
Returns the list of paths that have been modified.
show codeReturns:
- <Array>
Document.prototype.modifiedPaths = function () { var directModifiedPaths = Object.keys(this.$__.activePaths.states.modify); return directModifiedPaths.reduce(function (list, path) { var parts = path.split('.'); return list.concat(parts.reduce(function (chains, part, i) { return chains.concat(parts.slice(0, i).concat(part).join('.')); }, [])); }, []); };Document#populated(
path)Gets _id(s) used during population of the given
path.Parameters:
path<String>
show codeExample:
Model.findOne().populate('author').exec(function (err, doc) { console.log(doc.author.name) // Dr.Seuss console.log(doc.populated('author')) // '5144cf8050f071d979c118a7' })If the path was not populated, undefined is returned.
Document.prototype.populated = function( path, val, options ){ // val and options are internal //TODO: доделать эту проверку, она должна опираться не на $__.populated, а на то, что наш объект имеет родителя // и потом уже выставлять свойство populated == true if (null == val) { if (!this.$__.populated) return undefined; var v = this.$__.populated[path]; if (v) return v.value; return undefined; } // internal if (true === val) { if (!this.$__.populated) return undefined; return this.$__.populated[path]; } this.$__.populated || (this.$__.populated = {}); this.$__.populated[path] = { value: val, options: options }; return val; };Document#remove()
Удалить документ и вернуть коллекцию.
show codeDocument.prototype.remove = function(){ if ( this.collection ){ return this.collection.remove( this ); } return delete this; };Document#save(
[done])Saves this document.
Если апи-клиента нет и документ новый, то в колбэке будет plain object со всеми данными для сохранения на сервер.
Если апи-клиента нет и документ старое, то в колбэке будет plain object только с изменёнными данными.Parameters:
[done]<function(object)> <p>optional callback, object - objToSave</p>
Returns:
- <Deferred> <p>Deferred</p>
See:
show codeЕсли апи-клиент есть и не важно новый документ или старый, в колбэке всегда будет ответ от rest-api-client
// todo: доописать это дело
Сейчас если есть ресурс (апи клиент), то:
если документ новый, то после ответа создастся новый документ на основе ответа, и обовляется!!! (получше объяснить это) ссылка (id) внутри коллекции
если документ старый, то после ответа ищется этот документ по id и делается setDocument.prototype.save = function ( done ) { var self = this; var finalPromise = new Deferred().done( done ); // Сохранять документ можно только если он находится в коллекции if ( !this.collection ){ finalPromise.reject( arguments ); console.error('Document.save api handle is not implemented.'); return finalPromise; } // Check for preSave errors (точно знаю, что она проверяет ошибки в массивах (CastError)) var preSaveErr = self.$__presaveValidate(); if ( preSaveErr ) { finalPromise.reject( preSaveErr ); return finalPromise; } // Validate var p0 = new Deferred(); self.validate(function( err ){ if ( err ){ p0.reject( err ); finalPromise.reject( err ); } else { p0.resolve(); } }); // Сначала надо сохранить все поддокументы и сделать resolve!!! // (тут псевдосохранение смотреть EmbeddedDocument.prototype.save ) // Call save hooks on subdocs var subDocs = self.$__getAllSubdocs(); var whenCond = subDocs.map(function (d) {return d.save();}); whenCond.push( p0 ); // Так мы передаём массив promise условий var p1 = Deferred.when.apply( Deferred, whenCond ); p1.fail(function ( err ) { // If the initial insert fails provide a second chance. // (If we did this all the time we would break updates) if (self.$__.inserting) { self.isNew = true; self.emit('isNew', true); } finalPromise.reject( err ); }); // Handle save and results p1.done(function(){ self.$__handleSave().done(function(){ //todo: надо проверять, нужно ли писать проверку на наличие ресурса, если он есть - отдавать self, если нет, отдавать как сейчас написано // возможно и скорее всего, api и так отдаёт всё в правильном порядке (doc, meta, jqxhr) finalPromise.resolve.apply( finalPromise, arguments ); }).fail(function(){ finalPromise.reject.apply( finalPromise, arguments ); }); }); return finalPromise; };Document#set(
path,val,[type],[options])Sets the value of a path, or many paths.
Parameters:
show codeExample:
// path, value doc.set(path, value) // object doc.set({ path : value , path2 : { path : value } }) // only-the-fly cast to number doc.set(path, value, Number) // only-the-fly cast to string doc.set(path, value, String) // changing strict mode behavior doc.set(path, value, { strict: false });Document.prototype.set = function (path, val, type, options) { if (type && 'Object' === utils.getFunctionName(type.constructor)) { options = type; type = undefined; } var merge = options && options.merge , adhoc = type && true !== type , constructing = true === type , adhocs; var strict = options && 'strict' in options ? options.strict : this.$__.strictMode; if (adhoc) { adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {}); adhocs[path] = Schema.interpretAsType(path, type); } if ('string' !== typeof path) { // new Document({ key: val }) if (null === path || undefined === path) { var _temp = path; path = val; val = _temp; } else { var prefix = val ? val + '.' : ''; if (path instanceof Document) path = path._doc; var keys = Object.keys(path) , i = keys.length , pathtype , key; while (i--) { key = keys[i]; var pathName = prefix + key; pathtype = this.schema.pathType(pathName); if (null != path[key] // need to know if plain object - no Buffer, ObjectId, ref, etc && _.isPlainObject(path[key]) && ( !path[key].constructor || 'Object' === utils.getFunctionName(path[key].constructor) ) && 'virtual' !== pathtype && !(this.$__path(pathName) instanceof MixedSchema) && !(this.schema.paths[pathName] && this.schema.paths[pathName].options.ref)) { this.set(path[key], pathName, constructing); } else if (strict) { if ('real' === pathtype || 'virtual' === pathtype) { this.set(prefix + key, path[key], constructing); } else if ('throw' === strict) { throw new Error('Field `' + key + '` is not in schema.'); } } else if (undefined !== path[key]) { this.set(prefix + key, path[key], constructing); } } return this; } } // ensure _strict is honored for obj props // docschema = new Schema({ path: { nest: 'string' }}) // doc.set('path', obj); var pathType = this.schema.pathType(path); if ('nested' === pathType && val && _.isPlainObject(val) && (!val.constructor || 'Object' === utils.getFunctionName(val.constructor))) { if (!merge) this.setValue(path, null); this.set(val, path, constructing); return this; } var schema; var parts = path.split('.'); var subpath; if ('adhocOrUndefined' === pathType && strict) { // check for roots that are Mixed types var mixed; for (var i = 0; i < parts.length; ++i) { subpath = parts.slice(0, i+1).join('.'); schema = this.schema.path(subpath); if (schema instanceof MixedSchema) { // allow changes to sub paths of mixed types mixed = true; break; } } if (!mixed) { if ('throw' === strict) { throw new Error('Field `' + path + '` is not in schema.'); } return this; } } else if ('virtual' === pathType) { schema = this.schema.virtualpath(path); schema.applySetters(val, this); return this; } else { schema = this.$__path(path); } var pathToMark; // When using the $set operator the path to the field must already exist. // Else mongodb throws: "LEFT_SUBFIELD only supports Object" if (parts.length <= 1) { pathToMark = path; } else { for ( 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; } } if (!pathToMark) pathToMark = path; } // if this doc is being constructed we should not trigger getters var priorVal = constructing ? undefined : this.getValue(path); if (!schema || undefined === val) { this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal); return this; } var shouldSet = true; try { // If the user is trying to set a ref path to a document with // the correct model name, treat it as populated if (schema.options && schema.options.ref && val instanceof Document && schema.options.ref === val.schema.name) { //todo: need test (see https://github.com/Automattic/mongoose/pull/2387/files) this.populated(path, val._id); } val = schema.applySetters(val, this, false, priorVal); this.$markValid(path); } catch (e) { this.invalidate(path, new StorageError.CastError(schema.instance, val, path)); shouldSet = false; } if (shouldSet) { this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal); } return this; };Document#setValue(
path,value)Sets a raw value for a path (no casting, setters, transformations)
show codeDocument.prototype.setValue = function (path, value) { utils.setValue(path, value, this._doc); return this; };Document#toJSON(
options)The return value of this method is used in calls to JSON.stringify(doc).
Parameters:
options<Object>
Returns:
- <Object>
show codeThis method accepts the same options as Document#toObject. To apply the options to every document of your schema by default, set your schemas
toJSONoption to the same argument.schema.set('toJSON', { virtuals: true })See schema options for details.
Document.prototype.toJSON = function (options) { // check for object type since an array of documents // being stringified passes array indexes instead // of options objects. JSON.stringify([doc, doc]) // The second check here is to make sure that populated documents (or // subdocuments) use their own options for `.toJSON()` instead of their // parent's if (!(options && 'Object' == utils.getFunctionName(options.constructor)) || ((!options || options.json) && this.schema.options.toJSON)) { options = this.schema.options.toJSON ? utils.clone(this.schema.options.toJSON) : {}; } options.json = true; return this.toObject( options ); };Document#toObject(
[options])Converts this document into a plain javascript object, ready for storage in MongoDB.
Parameters:
[options]<Object>
Returns:
- <Object> <p>js object</p>
show codeBuffers are converted to instances of mongodb.Binary for proper storage.
Options:
gettersapply all getters (path and virtual getters)virtualsapply virtual getters (can overridegettersoption)minimizeremove empty objects (defaults to true)transforma transform function to apply to the resulting document before returning
Getters/Virtuals
Example of only applying path getters
doc.toObject({ getters: true, virtuals: false })Example of only applying virtual getters
doc.toObject({ virtuals: true })Example of applying both path and virtual getters
doc.toObject({ getters: true })To apply these options to every document of your schema by default, set your schemas
toObjectoption to the same argument.schema.set('toObject', { virtuals: true })Transform
We may need to perform a transformation of the resulting object based on some criteria, say to remove some sensitive information or return a custom object. In this case we set the optional
transformfunction.Transform functions receive three arguments
function (doc, ret, options) {}docThe mongoose document which is being convertedretThe plain object representation which has been convertedoptionsThe options in use (either schema options or the options passed inline)
Example
// specify the transform schema option if (!schema.options.toObject) schema.options.toObject = {}; schema.options.toObject.transform = function (doc, ret, options) { // remove the _id of every document before returning the result delete ret._id; } // without the transformation in the schema doc.toObject(); // { _id: 'anId', name: 'Wreck-it Ralph' } // with the transformation doc.toObject(); // { name: 'Wreck-it Ralph' }With transformations we can do a lot more than remove properties. We can even return completely new customized objects:
if (!schema.options.toObject) schema.options.toObject = {}; schema.options.toObject.transform = function (doc, ret, options) { return { movie: ret.name } } // without the transformation in the schema doc.toObject(); // { _id: 'anId', name: 'Wreck-it Ralph' } // with the transformation doc.toObject(); // { movie: 'Wreck-it Ralph' }Note: if a transform function returns
undefined, the return value will be ignored.Transformations may also be applied inline, overridding any transform set in the options:
function xform (doc, ret, options) { return { inline: ret.name, custom: true } } // pass the transform as an inline option doc.toObject({ transform: xform }); // { inline: 'Wreck-it Ralph', custom: true }Note: if you call
toObjectand pass any options, the transform declared in your schema options will not be applied. To force its application passtransform: trueif (!schema.options.toObject) schema.options.toObject = {}; schema.options.toObject.hide = '_id'; schema.options.toObject.transform = function (doc, ret, options) { if (options.hide) { options.hide.split(' ').forEach(function (prop) { delete ret[prop]; }); } } var doc = new Doc({ _id: 'anId', secret: 47, name: 'Wreck-it Ralph' }); doc.toObject(); // { secret: 47, name: 'Wreck-it Ralph' } doc.toObject({ hide: 'secret _id' }); // { _id: 'anId', secret: 47, name: 'Wreck-it Ralph' } doc.toObject({ hide: 'secret _id', transform: true }); // { name: 'Wreck-it Ralph' }Transforms are applied to the document and each of its sub-documents. To determine whether or not you are currently operating on a sub-document you might use the following guard:
if ('function' == typeof doc.ownerDocument) { // working with a sub doc }Transforms, like all of these options, are also available for
toJSON.See schema options for some more details.
During save, no custom options are applied to the document before being sent to the database.
retainKeyOrder - keep the key order of the doc save
var Checkin = new Schema({ ... }, { toObject: { retainKeyOrder: true } }); doc.toObject(); // object with correct order of the keys of doc // or inline doc.toObject({ retainKeyOrder: true }); // or if use toJSON(); var Checkin = new Schema({ ... }, { toJSON: { retainKeyOrder: true } }); doc.toJSON(); // JSON string with correct order of the keys of doc // or inline doc.toJSON({ retainKeyOrder: true });Document.prototype.toObject = function (options) { if (options && options.depopulate && this.$__.wasPopulated) { // populated paths that we set to a document return utils.clone(this._id, options); } // When internally saving this document we always pass options, // bypassing the custom schema options. var optionsParameter = options; if (!(options && 'Object' == utils.getFunctionName(options.constructor)) || (options && options._useSchemaOptions)) { options = this.schema.options.toObject ? clone(this.schema.options.toObject) : {}; } if ( options.minimize === undefined ){ options.minimize = this.schema.options.minimize; } if (!optionsParameter) { options._useSchemaOptions = true; } var ret = utils.clone(this._doc, options); if (options.virtuals || options.getters && false !== options.virtuals) { applyGetters(this, ret, 'virtuals', options); } if (options.getters) { applyGetters(this, ret, 'paths', options); // applyGetters for paths will add nested empty objects; // if minimize is set, we need to remove them. if (options.minimize) { ret = minimize(ret) || {}; } } // In the case where a subdocument has its own transform function, we need to // check and see if the parent has a transform (options.transform) and if the // child schema has a transform (this.schema.options.toObject) In this case, // we need to adjust options.transform to be the child schema's transform and // not the parent schema's var transform = options.transform; if (true === options.transform || (this.schema.options.toObject && options.transform)) { var opts = options.json ? this.schema.options.toJSON : this.schema.options.toObject; if (opts) { transform = (typeof options.transform === 'function' ? options.transform : opts.transform); } } if ('function' == typeof transform) { var xformed = transform(this, ret, options); if ('undefined' != typeof xformed) ret = xformed; } return ret; };Document#validate(
cb)Executes registered validation rules for this document.
Parameters:
cb<Function> <p>called after validation completes, passing an error if one occurred</p>
show codeNote:
This method is called
presave and if a validation rule is violated, save is aborted and the error is returned to yourcallback.Example:
doc.validate(function (err) { if (err) handleError(err); else // validation passed });Document.prototype.validate = function (cb) { var self = this; // only validate required fields when necessary var paths = Object.keys(this.$__.activePaths.states.require).filter(function (path) { if (!self.isSelected(path) && !self.isModified(path)) return false; return true; }); paths = paths.concat(Object.keys(this.$__.activePaths.states.init)); paths = paths.concat(Object.keys(this.$__.activePaths.states.modify)); paths = paths.concat(Object.keys(this.$__.activePaths.states.default)); if (0 === paths.length) { complete(); return this; } var validating = {} , total = 0; paths.forEach(validatePath); return this; function validatePath (path) { if (validating[path]) return; validating[path] = true; total++; utils.setImmediate(function(){ var p = self.schema.path(path); if (!p) return --total || complete(); var val = self.getValue(path); p.doValidate(val, function (err) { if (err) { self.invalidate( path , err , undefined //, true // embedded docs ); } --total || complete(); }, self); }); } function complete () { var err = self.$__.validationError; self.$__.validationError = undefined; cb && cb(err); } };Document#validateSync()
Executes registered validation rules (skipping asynchronous validators) for this document.
Returns:
- <StorageError> <p>StorageError if there are errors during validation, or undefined if there is no error.</p>
show codeNote:
This method is useful if you need synchronous validation.
Example:
var err = doc.validateSync(); if ( err ){ handleError( err ); } else { // validation passed }Document.prototype.validateSync = function () { var self = this; // only validate required fields when necessary var paths = Object.keys(this.$__.activePaths.states.require).filter(function (path) { if (!self.isSelected(path) && !self.isModified(path)) return false; return true; }); paths = paths.concat(Object.keys(this.$__.activePaths.states.init)); paths = paths.concat(Object.keys(this.$__.activePaths.states.modify)); paths = paths.concat(Object.keys(this.$__.activePaths.states.default)); var validating = {}; paths.forEach(function (path) { if (validating[path]) return; validating[path] = true; var p = self.schema.path(path); if (!p) return; if (!self.$isValid(path)) { return; } var val = self.getValue(path); var err = p.doValidateSync(val, self); if (err) { self.invalidate(path, err, undefined); } }); var err = self.$__.validationError; self.$__.validationError = undefined; //self.emit('validate', self); if (err) { for (var key in err.errors) { // Make sure cast errors persist if (err.errors[key] instanceof StorageError.CastError) { self.invalidate(key, err.errors[key]); } } } return err; };Document.$isValid(
path)Checks if a path is invalid
Parameters:
path<String> <p>the field to check</p>
Document.$markValid(
path)Marks a path as valid, removing existing validation errors.
Parameters:
path<String> <p>the field to mark as valid</p>
Document#errors
Hash containing current validation errors.
show codeDocument.prototype.errors; Document.prototype.adapterHooks = { documentDefineProperty: _.noop, documentSetInitialValue: _.noop, documentGetValue: _.noop, documentSetValue: _.noop };Document#id
The string version of this documents _id.
Note:
This getter exists on all documents by default. The getter can be disabled by setting the
idoption of itsSchemato false at construction time.show codenew Schema({ name: String }, { id: false });Document.prototype.id;See:
- error/cast.js
- error/messages.js
StorageError#msg
The default built-in validator error messages. These may be customized.
// customize within each schema or globally like so var mongoose = require('mongoose'); mongoose.Error.messages.String.enum = "Your custom message for {PATH}.";As you might have noticed, error messages support basic templating
{PATH}is replaced with the invalid document path{VALUE}is replaced with the invalid value{TYPE}is replaced with the validator type such as "regexp", "min", or "user defined"{MIN}is replaced with the declared min value for the Number.min validator{MAX}is replaced with the declared max value for the Number.max validator
Click the "show code" link below to see all defaults.
show codevar msg = module.exports = {}; msg.general = {}; msg.general.default = 'Validator failed for path `{PATH}` with value `{VALUE}`'; msg.general.required = 'Path `{PATH}` is required.'; msg.Number = {}; msg.Number.min = 'Path `{PATH}` ({VALUE}) is less than minimum allowed value ({MIN}).'; msg.Number.max = 'Path `{PATH}` ({VALUE}) is more than maximum allowed value ({MAX}).'; msg.Date = {}; msg.Date.min = 'Path `{PATH}` ({VALUE}) is before minimum allowed value ({MIN}).'; msg.Date.max = 'Path `{PATH}` ({VALUE}) is after maximum allowed value ({MAX}).'; msg.String = {}; msg.String.enum = '`{VALUE}` is not a valid enum value for path `{PATH}`.'; msg.String.match = 'Path `{PATH}` is invalid ({VALUE}).'; msg.String.minlength = 'Path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).'; msg.String.maxlength = 'Path `{PATH}` (`{VALUE}`) is longer than the maximum allowed length ({MAXLENGTH}).'; - error/validation.js
ValidationError(
instance)Document Validation Error
Parameters:
instance<Document>
show codeInherits:
function ValidationError (instance) { StorageError.call(this, 'Validation failed'); this.name = 'ValidationError'; this.errors = instance.errors = {}; if (instance && utils.getFunctionName(instance.constructor) === 'model') { //todo //StorageError.call(this, instance.constructor.modelName + " validation failed"); } else { StorageError.call(this, "Validation failed"); } this.name = 'ValidationError'; this.errors = {}; if (instance) { instance.errors = this.errors; } } - error/validator.js
ValidatorError(
properties)Schema validator error
Parameters:
properties<Object>
show codeInherits:
function ValidatorError (properties) { var msg = properties.message; if (!msg) { msg = errorMessages.general.default; } this.properties = properties; var message = this.formatMessage(msg, properties); StorageError.call(this, message); this.name = 'ValidatorError'; this.type = properties.type; this.path = properties.path; this.value = properties.value; } - error.js
StorageError.messages
The default built-in validator error messages.
show codeStorageError.messages = require('./error/messages');See:
= see.url || see.local Error.messages
- events.js
Events()
Backbone.Events
show codeA module that can be mixed in to any object in order to provide it with
custom events. You may bind withonor remove withoffcallback
functions to an event;trigger-ing an event fires all callbacks in
succession.var object = {};
_.extend(object, Events.prototype);
object.on('expand', function(){ alert('expanded'); });
object.trigger('expand');function Events() {} Events.prototype = {eventsApi(
obj,action,name,rest)Implement fancy features of the Events API such as multiple event
names"change blur"and jQuery-style event maps{change: action}
in terms of the existing API.show codeParameters:
objactionnamerest
var eventsApi = function(obj, action, name, rest) { if (!name) return true; // Handle event maps. if (typeof name === 'object') { for (var key in name) { obj[action].apply(obj, [key, name[key]].concat(rest)); } return false; } // Handle space separated event names. if (eventSplitter.test(name)) { var names = name.split(eventSplitter); for (var i = 0, l = names.length; i < l; i++) { obj[action].apply(obj, [names[i]].concat(rest)); } return false; } return true; };function Object() { [native code] }#off(
name,callback,context)Remove one or many callbacks. If
contextis null, removes all
callbacks with that function. Ifcallbackis null, removes all
callbacks for the event. Ifnameis null, removes all bound
callbacks for all events.show codeParameters:
namecallbackcontext
off: function(name, callback, context) { var retain, ev, events, names, i, l, j, k; if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; if (!name && !callback && !context) { this._events = {}; return this; } names = name ? [name] : _.keys(this._events); for (i = 0, l = names.length; i < l; i++) { name = names[i]; if (events = this._events[name]) { this._events[name] = retain = []; if (callback || context) { for (j = 0, k = events.length; j < k; j++) { ev = events[j]; if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || (context && context !== ev.context)) { retain.push(ev); } } } if (!retain.length) delete this._events[name]; } } return this; },function Object() { [native code] }#on(
name,callback,context)Bind an event to a
callbackfunction. Passing"all"will bind
the callback to all events fired.show codeParameters:
namecallbackcontext
on: function(name, callback, context) { if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; this._events || (this._events = {}); var events = this._events[name] || (this._events[name] = []); events.push({callback: callback, context: context, ctx: context || this}); return this; },function Object() { [native code] }#once(
name,callback,context)Bind an event to only be triggered a single time. After the first time
the callback is invoked, it will be removed.show codeParameters:
namecallbackcontext
once: function(name, callback, context) { if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; var once = _.once(function() { self.off(name, once); callback.apply(this, arguments); }); once._callback = callback; return this.on(name, once, context); },function Object() { [native code] }#stopListening(
obj,name,callback)Tell this object to stop listening to either specific events ... or
to every object it's currently listening to.show codeParameters:
objnamecallback
stopListening: function(obj, name, callback) { var listeningTo = this._listeningTo; if (!listeningTo) return this; var remove = !name && !callback; if (!callback && typeof name === 'object') callback = this; if (obj) (listeningTo = {})[obj._listenId] = obj; for (var id in listeningTo) { obj = listeningTo[id]; obj.off(name, callback, this); if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; } return this; } }; // Regular expression used to split event strings. var eventSplitter = /\s+/;function Object() { [native code] }#trigger(
name)Trigger one or many events, firing all bound callbacks. Callbacks are
passed the same arguments astriggeris, apart from the event name
(unless you're listening on"all", which will cause your callback to
receive the true name of the event as the first argument).show codeParameters:
name
trigger: function(name) { if (!this._events) return this; var args = Array.prototype.slice.call(arguments, 1); if (!eventsApi(this, 'trigger', name, args)) return this; var events = this._events[name]; var allEvents = this._events.all; if (events) triggerEvents(events, args); if (allEvents) triggerEvents(allEvents, arguments); return this; },triggerEvents(
events,args)A difficult-to-believe, but optimized internal dispatch function for
triggering events. Tries to keep the usual cases speedy (most internal
Backbone events have 3 arguments).show codeParameters:
eventsargs
var triggerEvents = function(events, args) { var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; switch (args.length) { case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); } }; var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; // Inversion-of-control versions of `on` and `once`. Tell *this* object to // listen to an event in another object ... keeping track of what it's // listening to. _.each(listenMethods, function(implementation, method) { Events[method] = function(obj, name, callback) { var listeningTo = this._listeningTo || (this._listeningTo = {}); var id = obj._listenId || (obj._listenId = _.uniqueId('l')); listeningTo[id] = obj; if (!callback && typeof name === 'object') callback = this; obj[implementation](name, callback, this); return this; }; }); module.exports = Events; - mpath.js
exports.get(
path,o,[special],[map])Returns the value of object
show codeoat the givenpath.exports.get = function (path, o, special, map) { var lookup; if ('function' === typeof special) { if (special.length < 2) { map = special; special = undefined; } else { lookup = special; special = undefined; } } map || (map = K); var parts = 'string' === typeof path ? path.split('.') : path; if (!Array.isArray(parts)) { throw new TypeError('Invalid `path`. Must be either string or array'); } var obj = o , part; for (var i = 0; i < parts.length; ++i) { part = parts[i]; if (Array.isArray(obj) && !/^\d+$/.test(part)) { // reading a property from the array items var paths = parts.slice(i); return obj.map(function (item) { return item ? exports.get(paths, item, special || lookup, map) : map(undefined); }); } if (lookup) { obj = lookup(obj, part); } else { obj = special && obj[special] ? obj[special][part] : obj[part]; } if (!obj) return map(obj); } return map(obj); };Parameters:
path<String>o<Object>[special]<String> <p>When this property name is present on any object in the path, walking will continue on the value of this property.</p>[map]<Function> <p>Optional function which receives each individual found value. The value returned from <code>map</code> is used in the original values place.</p>
Example:
var obj = { comments: [ { title: 'exciting!', _doc: { title: 'great!' }} , { title: 'number dos' } ] } mpath.get('comments.0.title', o) // 'exciting!' mpath.get('comments.0.title', o, '_doc') // 'great!' mpath.get('comments.title', o) // ['exciting!', 'number dos'] // summary mpath.get(path, o) mpath.get(path, o, special) mpath.get(path, o, map) mpath.get(path, o, special, map)exports.set(
path,val,o,[special],[map])Sets the
show codevalat the givenpathof objecto.exports.set = function (path, val, o, special, map, _copying) { var lookup; if ('function' === typeof special) { if (special.length < 2) { map = special; special = undefined; } else { lookup = special; special = undefined; } } map || (map = K); var parts = 'string' === typeof path ? path.split('.') : path; if (!Array.isArray(parts)) { throw new TypeError('Invalid `path`. Must be either string or array'); } if (null == o) return; // the existance of $ in a path tells us if the user desires // the copying of an array instead of setting each value of // the array to the one by one to matching positions of the // current array. var copy = _copying || /\$/.test(path) , obj = o , part; for (var i = 0, len = parts.length - 1; i < len; ++i) { part = parts[i]; if ('$' === part) { if (i == len - 1) { break; } else { continue; } } if (Array.isArray(obj) && !/^\d+$/.test(part)) { var paths = parts.slice(i); if (!copy && Array.isArray(val)) { for (var j = 0; j < obj.length && j < val.length; ++j) { // assignment of single values of array exports.set(paths, val[j], obj[j], special || lookup, map, copy); } } else { for (var j = 0; j < obj.length; ++j) { // assignment of entire value exports.set(paths, val, obj[j], special || lookup, map, copy); } } return; } if (lookup) { obj = lookup(obj, part); } else { obj = special && obj[special] ? obj[special][part] : obj[part]; } if (!obj) return; } // process the last property of the path part = parts[len]; // use the special property if exists if (special && obj[special]) { obj = obj[special]; } // set the value on the last branch if (Array.isArray(obj) && !/^\d+$/.test(part)) { if (!copy && Array.isArray(val)) { for (var item, j = 0; j < obj.length && j < val.length; ++j) { item = obj[j]; if (item) { if (lookup) { lookup(item, part, map(val[j])); } else { if (item[special]) item = item[special]; item[part] = map(val[j]); } } } } else { for (var j = 0; j < obj.length; ++j) { item = obj[j]; if (item) { if (lookup) { lookup(item, part, map(val)); } else { if (item[special]) item = item[special]; item[part] = map(val); } } } } } else { if (lookup) { lookup(obj, part, map(val)); } else { obj[part] = map(val); } } };Parameters:
path<String>valo<Object>[special]<String> <p>When this property name is present on any object in the path, walking will continue on the value of this property.</p>[map]<Function> <p>Optional function which is passed each individual value before setting it. The value returned from <code>map</code> is used in the original values place.</p>
- schema/array.js
SchemaArray#applyGetters(
value,scope)Overrides the getters application for the population special-case
show codeSchemaArray.prototype.applyGetters = function (value, scope) { if (this.caster.options && this.caster.options.ref) { // means the object id was populated return value; } return SchemaType.prototype.applyGetters.call(this, value, scope); };SchemaArray#cast(
value,doc,init)Casts values for set().
show codeParameters:
SchemaArray.prototype.cast = function ( value, doc, init ) { if (Array.isArray(value)) { if (!(value.isStorageArray)) { value = new StorageArray(value, this.path, doc); } if (this.caster) { try { for (var i = 0, l = value.length; i < l; i++) { value[i] = this.caster.cast(value[i], doc, init); } } catch (e) { // rethrow throw new CastError(e.type, value, this.path); } } return value; } else { // m-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); } };SchemaArray#checkRequired(
value)Check required
show codeParameters:
value<Array>
SchemaArray.prototype.checkRequired = function (value) { return !!(value && value.length); };SchemaArray(
key,cast,options)Array SchemaType constructor
Parameters:
key<String>cast<SchemaType>options<Object>
show codeInherits:
function SchemaArray (key, cast, options) { if (cast) { var castOptions = {}; if ('Object' === utils.getFunctionName( cast.constructor ) ) { if (cast.type) { // support { type: Woot } castOptions = _.clone( cast ); // do not alter user arguments delete castOptions.type; cast = cast.type; } else { cast = Mixed; } } // support { type: 'String' } var name = 'string' === typeof cast ? cast : utils.getFunctionName( cast ); var Caster = name in Types ? Types[name] : cast; this.casterConstructor = Caster; this.caster = new Caster(null, castOptions); // lazy load EmbeddedDoc || (EmbeddedDoc = require('../types/embedded')); if (!(this.caster instanceof EmbeddedDoc)) { this.caster.path = key; } } SchemaType.call(this, key, options); var self = this , defaultArr , fn; if (this.defaultValue) { defaultArr = this.defaultValue; fn = 'function' === typeof defaultArr; } this.default(function(){ var arr = fn ? defaultArr() : defaultArr || []; return new StorageArray(arr, self.path, this); }); } - schema/boolean.js
BooleanSchema(
path,options)Boolean SchemaType constructor.
show codeInherits:
function BooleanSchema (path, options) { SchemaType.call(this, path, options); }BooleanSchema#cast(
value)Casts to boolean
show codeParameters:
value<Object>
BooleanSchema.prototype.cast = function (value) { if (null === value) return value; if ('0' === value) return false; if ('true' === value) return true; if ('false' === value) return false; return !! value; };BooleanSchema#checkRequired()
Required validator
show codeBooleanSchema.prototype.checkRequired = function (value) { return value === true || value === false; }; - schema/buffer.js
SchemaBuffer#cast(
value,doc,init)Casts contents
show codeSchemaBuffer.prototype.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 (null == value) { 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 (!_.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 (Buffer.isBuffer(value)) { if (!value || !value.isStorageBuffer) { value = new StorageBuffer(value, [this.path, doc]); } return value; } else if (value instanceof Binary) { ret = new StorageBuffer(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 (null === value) return value; var type = typeof value; if ('string' === type || 'number' === type || Array.isArray(value)) { ret = new StorageBuffer(value, [this.path, doc]); return ret; } throw new CastError('buffer', value, this.path); };SchemaBuffer#checkRequired()
Check required
show codeSchemaBuffer.prototype.checkRequired = function (value, doc) { if (SchemaType._isRef(this, value, doc, true)) { return null != value; } else { return !!(value && value.length); } };SchemaBuffer(
key,cast)Buffer SchemaType constructor
Parameters:
key<String>cast<SchemaType>
show codeInherits:
function SchemaBuffer (key, options) { SchemaType.call(this, key, options, 'Buffer'); } - schema/date.js
DateSchema#cast(
value)Casts to date
show codeParameters:
value<Object> <p>to cast</p>
DateSchema.prototype.cast = function (value) { // If null or undefined if (value == null || value === '') return value; if (value instanceof Date) return value; var date; // support for timestamps if (typeof value !== 'undefined') { if (value instanceof Number || 'number' == typeof value || String(value) == Number(value)) { date = new Date(Number(value)); } else if (value.toString) { // support for date strings date = new Date(value.toString()); } if (date.toString() != 'Invalid Date') { return date; } } throw new CastError('date', value, this.path); };DateSchema#checkRequired()
Required validator for date
show codeDateSchema.prototype.checkRequired = function (value) { return value instanceof Date; };DateSchema(
key,options)Date SchemaType constructor.
show codeInherits:
function DateSchema (key, options) { SchemaType.call(this, key, options); } - schema/documentarray.js
DocumentArray#cast(
value,doc,init,prev)Casts contents
show codeParameters:
valuedoc<Document> <p>that triggers the casting</p>init<Boolean> <p>flag</p>prev<DocumentArray>
DocumentArray.prototype.cast = function (value, doc, init, prev) { var selected , subdoc , i; if (!Array.isArray(value)) { // m-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, prev); } // Если два массива примерно (кроме _id) одинаковые - не надо перезаписывать if ( prev && approximatelyEqual( value, prev ) ){ return prev; } if (!(value.isStorageDocumentArray)) { value = new StorageDocumentArray(value, this.path, doc); if (prev && prev._handlers) { for (var key in prev._handlers) { doc.off(key, prev._handlers[key]); } } } i = value.length; while (i--) { if (!(value[i] instanceof Subdocument) && value[i]) { if (init) { selected || (selected = scopePaths(this, doc.$__.selected, init)); subdoc = new this.casterConstructor(null, value, true, selected); value[i] = subdoc.init(value[i]); } else { try { subdoc = prev.id(value[i]._id); } catch(e) {} if (prev && subdoc) { // handle resetting doc with existing id but differing data // doc.array = [{ doc: 'val' }] subdoc.set(value[i]); } else { subdoc = new this.casterConstructor(value[i], value); restorePopulatedFields( subdoc, this.schema.tree, value[i], prev ); } // if set() is hooked it will have no return value // see gh-746 value[i] = subdoc; } } } return value; };DocumentArray(
key,schema,options)SubdocsArray SchemaType constructor
show codeInherits:
function DocumentArray (key, schema, options) { // compile an embedded document for this schema function EmbeddedDocument () { Subdocument.apply( this, arguments ); } EmbeddedDocument.prototype = Object.create( Subdocument.prototype ); EmbeddedDocument.prototype.constructor = EmbeddedDocument; EmbeddedDocument.prototype.$__setSchema( schema ); // apply methods for (var i in schema.methods) { EmbeddedDocument.prototype[i] = schema.methods[i]; } // apply statics for (var j in schema.statics) { EmbeddedDocument[j] = schema.statics[j]; } EmbeddedDocument.options = options; this.schema = schema; ArrayType.call(this, key, EmbeddedDocument, options); this.schema = schema; var path = this.path; var fn = this.defaultValue; this.default(function(){ var arr = fn.call(this); if (!Array.isArray(arr)) arr = [arr]; return new StorageDocumentArray(arr, path, this); }); }DocumentArray#doValidate()
Performs local validations first, then validations on each embedded doc
show codeDocumentArray.prototype.doValidate = function (array, fn, scope) { var self = this; SchemaType.prototype.doValidate.call(this, array, function (err) { if (err) return fn(err); var count = array && array.length , error; if (!count) return fn(); // 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) { // sidestep sparse entries var doc = array[i]; if (!doc) { --count || fn(); continue; } !(function (i) { doc.validate(function (err) { if (err && !error) { // rewrite the key err.key = self.key + '.' + i + '.' + err.key; return fn(error = err); } --count || fn(); }); })(i); } }, scope); };DocumentArray#doValidateSync()
Performs local validations first, then validations on each embedded doc.
Returns:
show codeNote:
This method ignores the asynchronous validators.
DocumentArray.prototype.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; }; - schema/mixed.js
Mixed#cast(
value)Casts
valfor Mixed.Parameters:
value<Object> <p>to cast</p>
show codethis is a no-op
Mixed.prototype.cast = function (value) { return value; };Mixed#checkRequired()
Required validator
show codeMixed.prototype.checkRequired = function (val) { return (val !== undefined) && (val !== null); };Mixed(
path,options)Mixed SchemaType constructor.
show codeInherits:
function Mixed (path, options) { if (options && options.default) { var def = options.default; if (Array.isArray(def) && 0 === def.length) { // make sure empty array defaults are handled options.default = Array; } else if (!options.shared && _.isPlainObject(def) && 0 === Object.keys(def).length) { // prevent odd "shared" objects between documents options.default = function () { return {}; }; } } SchemaType.call(this, path, options); } - schema/number.js
NumberSchema#cast(
value)Casts to number
show codeParameters:
value<Object> <p>value to cast</p>
NumberSchema.prototype.cast = function ( value ) { var val = value && value._id ? value._id // documents : value; if (!isNaN(val)){ if (null === val) return val; if ('' === val) return null; if ('string' === typeof val) val = Number(val); if (val instanceof Number) return val; if ('number' === typeof val) return val; if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) { return new Number(val); } } throw new CastError('number', value, this.path); };NumberSchema#checkRequired()
Required validator for number
show codeNumberSchema.prototype.checkRequired = function ( value ) { if ( SchemaType._isRef( this, value ) ) { return null != value; } else { return typeof value === 'number' || value instanceof Number; } };NumberSchema#max(
value,[message])Sets a maximum number validator.
Parameters:
Returns:
- <SchemaType> <p>this</p>
show codeExample:
var s = new Schema({ n: { type: Number, max: 10 }) var M = db.model('M', s) var m = new M({ n: 11 }) m.save(function (err) { console.error(err) // validator error m.n = 10; m.save() // success }) // custom error messages // We can also use the special {MAX} token which will be replaced with the invalid value var max = [10, 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).']; var schema = new Schema({ n: { type: Number, max: max }) var M = mongoose.model('Measurement', schema); var s= new M({ n: 4 }); s.validate(function (err) { console.log(String(err)) // ValidationError: The value of path `n` (4) exceeds the limit (10). })NumberSchema.prototype.max = function (value, message) { if (this.maxValidator) { this.validators = this.validators.filter(function(v){ return v.validator != this.maxValidator; }, this); } if (null != value) { var msg = message || errorMessages.Number.max; msg = msg.replace(/{MAX}/, value); this.validators.push({ validator: this.maxValidator = function(v) { return v === null || v <= value; }, message: msg, type: 'max' }); } return this; };NumberSchema#min(
value,[message])Sets a minimum number validator.
Parameters:
Returns:
- <SchemaType> <p>this</p>
show codeExample:
var s = new Schema({ n: { type: Number, min: 10 }) var M = db.model('M', s) var m = new M({ n: 9 }) m.save(function (err) { console.error(err) // validator error m.n = 10; m.save() // success }) // custom error messages // We can also use the special {MIN} token which will be replaced with the invalid value var min = [10, 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).']; var schema = new Schema({ n: { type: Number, min: min }) var M = mongoose.model('Measurement', schema); var s= new M({ n: 4 }); s.validate(function (err) { console.log(String(err)) // ValidationError: The value of path `n` (4) is beneath the limit (10). })NumberSchema.prototype.min = function (value, message) { if (this.minValidator) { this.validators = this.validators.filter(function (v) { return v.validator != this.minValidator; }, this); } if (null != value) { var msg = message || errorMessages.Number.min; msg = msg.replace(/{MIN}/, value); this.validators.push({ validator: this.minValidator = function (v) { return v === null || v >= value; }, message: msg, type: 'min' }); } return this; };NumberSchema(
key,options)Number SchemaType constructor.
show codeInherits:
function NumberSchema (key, options) { SchemaType.call(this, key, options, 'Number'); } - schema/objectid.js
ObjectId#auto(
turnOn)Adds an auto-generated ObjectId default if turnOn is true.
Parameters:
turnOn<Boolean> <p>auto generated ObjectId defaults</p>
show codeReturns:
- <SchemaType> <p>this</p>
ObjectId.prototype.auto = function ( turnOn ) { if ( turnOn ) { this.default( defaultId ); this.set( resetId ); } return this; };ObjectId#cast(
value,doc,init,priorVal)Casts to ObjectId
show codeObjectId.prototype.cast = function ( value, doc, init, priorVal ) { // lazy load Document || (Document = require('./../document')); if ( SchemaType._isRef( this, value ) ) { // wait! we may need to cast this to a document // If null or undefined if (null == value) { return value; } if (value instanceof Document) { value.$__.wasPopulated = true; return value; } // setting a populated path if (value instanceof oid ) { return value; } else if ( !_.isPlainObject( value ) ) { throw new CastError('ObjectId', value, this.path); } // Нужно создать документ по схеме, указанной в ссылке var schema = this.options.ref; if ( !schema ){ throw new TypeError('При ссылке (ref) на документ ' + 'нужно указывать схему, по которой этот документ создавать'); } if ( !storage.schemas[ schema ] ){ throw new TypeError('При ссылке (ref) на документ ' + 'нужно указывать название схемы на которую ссылаемся при её создании ( new Schema("name", schemaObject) )'); } // init doc doc = new Document( value, undefined, storage.schemas[ schema ], undefined, true ); doc.$__.wasPopulated = true; return doc; } if (value === null) return value; // Предотвратить depopulate if ( priorVal instanceof Document ){ if ( priorVal._id && priorVal._id.equals( value ) ){ return priorVal; } } if (value instanceof oid) return value; if ( value._id && value._id instanceof oid ) return value._id; if (value.toString) { try { return oid.createFromHexString(value.toString()); } catch (err) { throw new CastError('ObjectId', value, this.path); } } throw new CastError('ObjectId', value, this.path); };ObjectId#checkRequired()
Check required
show codeObjectId.prototype.checkRequired = function ( value ) { if (SchemaType._isRef( this, value )) { return null != value; } else { return value instanceof oid; } };ObjectId(
key,options)ObjectId SchemaType constructor.
show codeInherits:
function ObjectId (key, options) { SchemaType.call(this, key, options, 'ObjectId'); } - schema/string.js
StringSchema#cast()
Casts to String
show codeStringSchema.prototype.cast = function ( value ) { if ( value === null ) { return value; } if ('undefined' !== typeof value) { // handle documents being passed if (value._id && 'string' === typeof value._id) { return value._id; } if ( value.toString ) { return value.toString(); } } throw new CastError('string', value, this.path); };StringSchema#checkRequired(
value)Check required
show codeParameters:
value<String>
StringSchema.prototype.checkRequired = function checkRequired (value, doc) { if (SchemaType._isRef(this, value, doc, true)) { return null != value; } else { return (value instanceof String || typeof value === 'string') && value.length; } };StringSchema#enum(
[args...])Adds an enum validator
Returns:
- <SchemaType> <p>this</p>
show codeExample:
var states = 'opening open closing closed'.split(' ') var s = new Schema({ state: { type: String, enum: states }}) var M = db.model('M', s) var m = new M({ state: 'invalid' }) m.save(function (err) { console.error(String(err)) // ValidationError: `invalid` is not a valid enum value for path `state`. m.state = 'open' m.save(callback) // success }) // or with custom error messages var enu = { values: 'opening open closing closed'.split(' '), message: 'enum validator failed for path `{PATH}` with value `{VALUE}`' } var s = new Schema({ state: { type: String, enum: enu }) var M = db.model('M', s) var m = new M({ state: 'invalid' }) m.save(function (err) { console.error(String(err)) // ValidationError: enum validator failed for path `state` with value `invalid` m.state = 'open' m.save(callback) // success })StringSchema.prototype.enum = function () { if (this.enumValidator) { this.validators = this.validators.filter(function(v) { return v.validator != this.enumValidator; }, this); this.enumValidator = false; } if (undefined === arguments[0] || false === arguments[0]) { return this; } var values; var errorMessage; if (_.isPlainObject(arguments[0])) { values = arguments[0].values; errorMessage = arguments[0].message; } else { values = arguments; errorMessage = errorMessages.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' }); return this; };StringSchema#lowercase()
Adds a lowercase setter.
Returns:
- <SchemaType> <p>this</p>
show codeExample:
var s = new Schema({ email: { type: String, lowercase: true }}) var M = db.model('M', s); var m = new M({ email: 'SomeEmail@example.COM' }); console.log(m.email) // someemail@example.comStringSchema.prototype.lowercase = function () { return this.set(function (v, self) { if ('string' !== typeof v) v = self.cast(v); if (v) return v.toLowerCase(); return v; }); };StringSchema#match(
regExp,[message])Sets a regexp validator.
Parameters:
Returns:
- <SchemaType> <p>this</p>
show codeAny value that does not pass
regExp.test(val) will fail validation.Example:
var s = new Schema({ name: { type: String, match: /^a/ }}) var M = db.model('M', s) var m = new M({ name: 'I am invalid' }) m.validate(function (err) { console.error(String(err)) // "ValidationError: Path `name` is invalid (I am invalid)." m.name = 'apples' m.validate(function (err) { assert.ok(err) // success }) }) // using a custom error message var match = [ /\.html$/, "That file doesn't end in .html ({VALUE})" ]; var s = new Schema({ file: { type: String, match: match }}) var M = db.model('M', s); var m = new M({ file: 'invalid' }); m.validate(function (err) { console.log(String(err)) // "ValidationError: That file doesn't end in .html (invalid)" })Empty strings,
undefined, andnullvalues always pass the match validator. If you require these values, enable therequiredvalidator also.var s = new Schema({ name: { type: String, match: /^a/, required: true }})StringSchema.prototype.match = function match (regExp, message) { // yes, we allow multiple match validators var msg = message || errorMessages.String.match; var matchValidator = function(v) { var ret = ((null != v && '' !== v) ? regExp.test(v) : true); return ret; }; this.validators.push({ validator: matchValidator, message: msg, type: 'regexp' }); return this; };StringSchema(
key,options)String SchemaType constructor.
show codeInherits:
function StringSchema (key, options) { this.enumValues = []; this.regExp = null; SchemaType.call(this, key, options, 'String'); }StringSchema#trim()
Adds a trim setter.
Returns:
- <SchemaType> <p>this</p>
show codeThe string value will be trimmed when set.
Example:
var s = new Schema({ name: { type: String, trim: true }}) var M = db.model('M', s) var string = ' some name ' console.log(string.length) // 11 var m = new M({ name: string }) console.log(m.name.length) // 9StringSchema.prototype.trim = function () { return this.set(function (v, self) { if ('string' !== typeof v) v = self.cast(v); if (v) return v.trim(); return v; }); };StringSchema#uppercase()
Adds an uppercase setter.
Returns:
- <SchemaType> <p>this</p>
show codeExample:
var s = new Schema({ caps: { type: String, uppercase: true }}) var M = db.model('M', s); var m = new M({ caps: 'an example' }); console.log(m.caps) // AN EXAMPLEStringSchema.prototype.uppercase = function () { return this.set(function (v, self) { if ('string' !== typeof v) v = self.cast(v); if (v) return v.toUpperCase(); return v; }); }; - schema.js
Schema#add(
obj,[prefix])Adds key path / schema type pairs to this schema.
show codeExample:
var ToySchema = new Schema; ToySchema.add({ name: 'string', color: 'string', price: 'number' });Schema.prototype.add = function add ( obj, prefix ) { prefix = prefix || ''; var keys = Object.keys( obj ); for (var i = 0; i < keys.length; ++i) { var key = keys[i]; if (null == obj[ key ]) { throw new TypeError('Invalid value for schema path `'+ prefix + key +'`'); } if ( _.isPlainObject(obj[key] ) && ( !obj[ key ].constructor || 'Object' === utils.getFunctionName(obj[key].constructor) ) && ( !obj[ key ].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 { this.path( prefix + key, obj[ key ] ); // mixed type } } else { this.path( prefix + key, obj[ key ] ); } } };Schema#defaultOptions(
options)Returns default options for this schema, merged with
options.Parameters:
options<Object>
show codeReturns:
- <Object>
Schema.prototype.defaultOptions = function (options) { options = _.assign({ strict: true , versionKey: '__v' , discriminatorKey: '__t' , minimize: true // the following are only applied at construction time , _id: true , id: true }, options ); return options; };Schema#discriminator(
name,schema)Schema inheritance
this - baseSchemashow codeExample:
var PersonSchema = new Schema('Person', { name: String, createdAt: Date }); var BossSchema = new Schema('Boss', PersonSchema, { department: String });Schema.prototype.discriminator = function discriminator (name, schema) { if (!(schema instanceof Schema)) { throw new Error('You must pass a valid discriminator Schema'); } if ( this.discriminatorMapping && !this.discriminatorMapping.isRoot ) { throw new Error('Discriminator "' + name + '" can only be a discriminator of the root model'); } var key = this.options.discriminatorKey; if ( schema.path(key) ) { throw new Error('Discriminator "' + name + '" cannot have field with name "' + key + '"'); } // merges base schema into new discriminator schema and sets new type field. (function mergeSchemas(schema, baseSchema) { utils.merge(schema, baseSchema); var obj = {}; obj[key] = { type: String, default: name }; schema.add(obj); schema.discriminatorMapping = { key: key, value: name, isRoot: false }; // throws error if options are invalid (function validateOptions(a, b) { a = utils.clone(a); b = utils.clone(b); delete a.toJSON; delete a.toObject; delete b.toJSON; delete b.toObject; if (!utils.deepEqual(a, b)) { throw new Error('Discriminator options are not customizable (except toJSON & toObject)'); } })(schema.options, baseSchema.options); var toJSON = schema.options.toJSON , toObject = schema.options.toObject; schema.options = utils.clone(baseSchema.options); if (toJSON) schema.options.toJSON = toJSON; if (toObject) schema.options.toObject = toObject; //schema.callQueue = baseSchema.callQueue.concat(schema.callQueue); schema._requiredpaths = undefined; // reset just in case Schema#requiredPaths() was called on either schema })(schema, this); if (!this.discriminators) { this.discriminators = {}; } if (!this.discriminatorMapping) { this.discriminatorMapping = { key: key, value: null, isRoot: true }; } if (this.discriminators[name]) { throw new Error('Discriminator with name "' + name + '" already exists'); } this.discriminators[name] = schema; // Register methods and statics for ( var m in this.methods ){ schema.methods[ m ] = this.methods[ m ]; } for ( var s in this.statics ){ schema.statics[ s ] = this.methods[ s ]; } return this.discriminators[name]; };Schema#eachPath(
fn)Iterates the schemas paths similar to Array#forEach.
Parameters:
fn<Function> <p>callback function</p>
Returns:
- <Schema> <p>this</p>
show codeThe callback is passed the pathname and schemaType as arguments on each iteration.
Schema.prototype.eachPath = function (fn) { var keys = Object.keys(this.paths) , len = keys.length; for (var i = 0; i < len; ++i) { fn(keys[i], this.paths[keys[i]]); } return this; };Schema#get(
key)Gets a schema option.
show codeParameters:
key<String> <p>option name</p>
Schema.prototype.get = function (key) { return this.options[key]; };Schema#method(
method,[fn])Adds an instance method to documents constructed from Models compiled from this schema.
show codeExample
var schema = kittySchema = new Schema(..); schema.method('meow', function () { console.log('meeeeeoooooooooooow'); }) var Kitty = mongoose.model('Kitty', schema); var fizz = new Kitty; fizz.meow(); // meeeeeooooooooooooowIf a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.
schema.method({ purr: function () {} , scratch: function () {} }); // later fizz.purr(); fizz.scratch();Schema.prototype.method = function (name, fn) { if ('string' !== typeof name) { for (var i in name) { this.methods[i] = name[i]; } } else { this.methods[name] = fn; } return this; };Schema#path(
path,constructor)Gets/sets schema paths.
show codeSets a path (if arity 2)
Gets a path (if arity 1)Example
schema.path('name') // returns a SchemaType schema.path('name', Number) // changes the schemaType of `name` to NumberSchema.prototype.path = function (path, obj) { if (obj === undefined) { if (this.paths[path]) return this.paths[path]; if (this.subpaths[path]) return this.subpaths[path]; // subpaths? return /\.\d+\.?.*$/.test(path) ? getPositionalPath(this, path) : undefined; } // some path names conflict with document methods if (reserved[path]) { throw new Error('`' + path + '` may not be used as a schema pathname'); } // update the tree var subpaths = path.split(/\./) , last = subpaths.pop() , branch = this.tree; subpaths.forEach(function(sub, i) { if (!branch[sub]) branch[sub] = {}; if ('object' !== typeof branch[sub]) { 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); return this; };Schema#pathType(
path)Returns the pathType of
pathfor this schema.Parameters:
path<String>
Returns:
- <String>
show codeGiven a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path.
Schema.prototype.pathType = function (path) { if (path in this.paths) return 'real'; if (path in this.virtuals) return 'virtual'; if (path in this.nested) return 'nested'; if (path in this.subpaths) return 'real'; if (/\.\d+\.|\.\d+$/.test(path) && getPositionalPath(this, path)) { return 'real'; } else { return 'adhocOrUndefined'; } };Schema#plugin(
plugin,opts)Registers a plugin for this schema.
show codeSee:
Schema.prototype.plugin = function (fn, opts) { fn(this, opts); return this; };Schema#post(
method,fn)Defines a post for the document
See:
show codePost hooks fire
onthe event emitted from document instances of Models compiled from this schema.var schema = new Schema(..); schema.post('save', function (doc) { console.log('this fired after a document was saved'); }); var Model = mongoose.model('Model', schema); var m = new Model(..); m.save(function (err) { console.log('this fires after the `post` hook'); });Schema.prototype.post = function(method, fn){ return this.queue('on', arguments); };Schema#pre(
method,callback)Defines a pre hook for the document.
See:
show codeExample
var toySchema = new Schema(..); toySchema.pre('save', function (next) { if (!this.created) this.created = new Date; next(); }) toySchema.pre('validate', function (next) { if (this.name != 'Woody') this.name = 'Woody'; next(); })Schema.prototype.pre = function(){ return this.queue('pre', arguments); };Schema#queue(
name,args)Adds a method call to the queue.
show codeParameters:
Schema.prototype.queue = function(name, args){ this.callQueue.push([name, args]); return this; };Schema#requiredPaths()
Returns an Array of path strings that are required by this schema.
show codeReturns:
- <Array>
Schema.prototype.requiredPaths = function requiredPaths () { if (this._requiredpaths) return this._requiredpaths; var paths = Object.keys(this.paths) , i = paths.length , ret = []; while (i--) { var path = paths[i]; if (this.paths[path].isRequired) ret.push(path); } this._requiredpaths = ret; return this._requiredpaths; };Schema(
[name],[baseSchema],obj,[options])Schema constructor.
Parameters:
show codeExample:
var child = new Schema({ name: String }); var schema = new Schema({ name: String, age: Number, children: [child] }); var Tree = mongoose.model('Tree', schema); // setting schema options new Schema({ name: String }, { _id: false, autoIndex: false })Options:
- id: bool - defaults to true
minimize: bool - controls document#toObject behavior when called manually - defaults to true- strict: bool - defaults to true
- toJSON - object - no default
- toObject - object - no default
- versionKey: bool - defaults to "__v"
Note:
When nesting schemas, (
childrenin the example above), always declare the child schema first before passing it into is parent.function Schema ( name, baseSchema, obj, options ) { if ( !(this instanceof Schema) ) { return new Schema( name, baseSchema, obj, options ); } // Если это именованая схема if ( typeof name === 'string' ){ this.name = name; schemas[ name ] = this; } else { options = obj; obj = baseSchema; baseSchema = name; name = undefined; } if ( !(baseSchema instanceof Schema) ){ options = obj; obj = baseSchema; baseSchema = undefined; } //todo: зачем оно нужно? проблема: obj становится как у прошлой схемы + текущее, из-за этого source, // потому что оно копируется из старой схемы в текущий source, а так как он ссылается на obj, // и в js у нас разделение памяти, то obj расширяется полями source из старой схемы. // Сохраним описание схемы для поддержки дискриминаторов //this.source = obj; this.paths = {}; this.subpaths = {}; this.virtuals = {}; this.nested = {}; this.inherits = {}; this.callQueue = []; this.methods = {}; this.statics = {}; this.tree = {}; this._requiredpaths = undefined; this.discriminatorMapping = undefined; this.options = this.defaultOptions( options ); if ( baseSchema instanceof Schema ){ baseSchema.discriminator( name, this ); } // build paths if ( obj ) { this.add( obj ); } // check if _id's value is a subdocument (m-gh-2276) var _idSubDoc = obj && obj._id && _.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) { this.add({ _id: {type: Schema.ObjectId, auto: true} }); } // ensure the documents receive an id getter unless disabled var autoid = !this.paths['id'] && this.options.id; if ( autoid ) { this.virtual('id').get( idGetter ); } // adds updatedAt and createdAt timestamps to documents if enabled var timestamps = this.options.timestamps; if (timestamps) { var createdAt = timestamps.createdAt || 'createdAt' , updatedAt = timestamps.updatedAt || 'updatedAt' , schemaAdditions = {}; schemaAdditions[updatedAt] = Date; if (!this.paths[createdAt]) { schemaAdditions[createdAt] = Date; } this.add(schemaAdditions); //todo: //this.pre('save', function (next) { // var defaultTimestamp = new Date(); // // if (!this[createdAt]){ // this[createdAt] = auto_id ? this._id.getTimestamp() : defaultTimestamp; // } // // this[updatedAt] = this.isNew ? this[createdAt] : defaultTimestamp; // // next(); //}); } }Schema#set(
key,[value])Sets/gets a schema option.
show codeParameters:
Schema.prototype.set = function (key, value) { if (1 === arguments.length) { return this.options[key]; } this.options[key] = value; return this; };Schema#static(
name,fn)Adds static "class" methods to Models compiled from this schema.
show codeExample
var schema = new Schema(..); schema.static('findByName', function (name, callback) { return this.find({ name: name }, callback); }); var Drink = mongoose.model('Drink', schema); Drink.findByName('sanpellegrino', function (err, drinks) { // });If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.
Schema.prototype.static = function(name, fn) { if ('string' !== typeof name) { for (var i in name) { this.statics[i] = name[i]; } } else { this.statics[name] = fn; } return this; };Schema#virtual(
name,[options])Creates a virtual type with the given name.
show codeReturns:
Schema.prototype.virtual = function (name, options) { var virtuals = this.virtuals; var parts = name.split('.'); 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]; };Schema#virtualpath(
name)Returns the virtual type with the given
name.Parameters:
name<String>
show codeReturns:
Schema.prototype.virtualpath = function (name) { return this.virtuals[name]; };Schema.interpretAsType(
path,obj)Converts type arguments into Schema Types.
show codeSchema.interpretAsType = function (path, obj) { var constructorName = utils.getFunctionName(obj.constructor); if (constructorName !== 'Object'){ obj = { type: obj }; } // Get the type making sure to allow keys named "type" // and default to mixed if not specified. // { type: { type: String, default: 'freshcut' } } var type = obj.type && !obj.type.type ? obj.type : {}; if ('Object' === utils.getFunctionName(type.constructor) || 'mixed' == type) { return new Types.Mixed(path, obj); } if (Array.isArray(type) || Array == type || 'array' == type) { // if it was specified through { type } look for `cast` var cast = (Array == type || 'array' == type) ? obj.cast : type[0]; if (cast instanceof Schema) { return new Types.DocumentArray(path, cast, obj); } if ('string' == typeof cast) { cast = Types[cast.charAt(0).toUpperCase() + cast.substring(1)]; } else if (cast && (!cast.type || cast.type.type) && 'Object' === utils.getFunctionName(cast.constructor) && Object.keys(cast).length) { return new Types.DocumentArray(path, new Schema(cast), obj); } return new Types.Array(path, cast || Types.Mixed, obj); } var name = 'string' === typeof type ? type // If not string, `type` is a function. Outside of IE, function.name // gives you the function name. In IE, you need to compute it : utils.getFunctionName(type); if (name) { name = name.charAt(0).toUpperCase() + name.substring(1); } if (undefined == Types[name]) { throw new TypeError('Undefined type at `' + path + '` Did you try nesting Schemas? ' + 'You can only nest using refs or arrays.'); } return new Types[name](path, obj); };Schema.reserved
Reserved document keys.
show codeSchema.reserved = Object.create( null ); var reserved = Schema.reserved; reserved.on = reserved.get = reserved.set = reserved.init = reserved.isNew = reserved.errors = reserved.schema = reserved.options = reserved.toObject = reserved.trigger = // Events reserved.off = // Events reserved._events = // EventsKeys in this object are names that are rejected in schema declarations b/c they conflict with mongoose functionality. Using these key name will throw an error.
on, emit, _events, db, get, set, init, isNew, errors, schema, options, _pres, _posts, toObjectNOTE: Use of these terms as method names is permitted, but play at your own risk, as they may be existing mongoose document methods you are stomping on.
var schema = new Schema(..); schema.methods.init = function () {} // potentially breakingSchema.Types
The various built-in Storage Schema Types.
show codeSchema.Types = require('./schema/index'); // Хранилище схем Schema.schemas = schemas = {};Example:
var mongoose = require('mongoose'); var ObjectId = mongoose.Schema.Types.ObjectId;Types:
Using this exposed access to the
MixedSchemaType, we can use them in our schema.var Mixed = mongoose.Schema.Types.Mixed; new mongoose.Schema({ _user: Mixed })Schema#paths
Schema as flat paths
Example:
show code{ '_id' : SchemaType, , 'nested.key' : SchemaType, }Schema.prototype.paths;Schema#tree
Schema as a tree
Example:
show code{ '_id' : ObjectId , 'nested' : { 'key' : String } }Schema.prototype.tree; - schematype.js
SchemaType#applyGetters(
value,scope)Applies getters to a value
show codeSchemaType.prototype.applyGetters = function( value, scope ){ if ( SchemaType._isRef( this, value ) ) return value; var v = value , getters = this.getters , len = getters.length; if ( !len ) { return v; } while ( len-- ) { v = getters[ len ].call(scope, v, this); } return v; };SchemaType#applySetters(
value,scope,init,priorVal)Applies setters
show codeSchemaType.prototype.applySetters = function (value, scope, init, priorVal) { if (SchemaType._isRef( this, value )) { return init ? value : this.cast(value, scope, init, priorVal); } var v = value , setters = this.setters , len = setters.length , caster = this.caster; if (Array.isArray(v) && caster && caster.setters) { for (var i = 0; i < v.length; i++) { v[i] = caster.applySetters(v[i], scope, init, priorVal); } } if (!len) { if (null === v || undefined === v) return v; return this.cast(v, scope, init, priorVal); } while (len--) { v = setters[len].call(scope, v, this); } if (null === v || undefined === v) return v; // do not cast until all setters are applied #665 v = this.cast(v, scope, init, priorVal); return v; };SchemaType#default(
val)Sets a default value for this SchemaType.
Parameters:
val<Function, T> <p>the default value</p>
Returns:
show codeExample:
var schema = new Schema({ n: { type: Number, default: 10 }) var M = db.model('M', schema) var m = new M; console.log(m.n) // 10Defaults can be either
functionswhich return the value to use as the default or the literal value itself. Either way, the value will be cast based on its schema type before being set during document creation.Example:
// values are cast: var schema = new Schema({ aNumber: Number, default: "4.815162342" }) var M = db.model('M', schema) var m = new M; console.log(m.aNumber) // 4.815162342 // default unique objects for Mixed types: var schema = new Schema({ mixed: Schema.Types.Mixed }); schema.path('mixed').default(function () { return {}; }); // if we don't use a function to return object literals for Mixed defaults, // each document will receive a reference to the same object literal creating // a "shared" object instance: var schema = new Schema({ mixed: Schema.Types.Mixed }); schema.path('mixed').default({}); var M = db.model('M', schema); var m1 = new M; m1.mixed.added = 1; console.log(m1.mixed); // { added: 1 } var m2 = new M; console.log(m2.mixed); // { added: 1 }SchemaType.prototype.default = function (val) { if (1 === arguments.length) { this.defaultValue = typeof val === 'function' ? val : this.cast( val ); return this; } else if ( arguments.length > 1 ) { this.defaultValue = _.toArray( arguments ); } return this.defaultValue; };SchemaType#doValidate(
value,callback,scope)Performs a validation of
show codevalueusing the validators declared for this SchemaType.SchemaType.prototype.doValidate = function (value, callback, scope) { var err = false , path = this.path , count = this.validators.length; if (!count) return callback(null); var validate = function validate(ok, validatorProperties) { if (err) return; if (ok === undefined || ok) { --count || callback(null); } else { err = new ValidatorError(validatorProperties); callback(err); } }; var self = this; this.validators.forEach(function (v) { if (err) { return; } var validator = v.validator; var message = v.message; var type = v.type; var validatorProperties = utils.clone(v); validatorProperties.path = path; validatorProperties.value = value; if (validator instanceof RegExp) { validate(validator.test(value), validatorProperties); } else if ('function' === typeof validator) { if (value === undefined && !self.isRequired) { validate(true, validatorProperties); return; } if (2 === validator.length) { validator.call(scope, value, function (ok) { validate(ok, validatorProperties); }); } else { validate(validator.call(scope, value), validatorProperties); } } }); };SchemaType#doValidateSync(
value,scope)Performs a validation of
valueusing the validators declared for this SchemaType.Parameters:
value<T>scope<Object>
Returns:
show codeNote:
This method ignores the asynchronous validators.
SchemaType.prototype.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) { } else { err = new ValidatorError(validatorProperties); } }; var self = this; if (value === undefined && !self.isRequired) { return null; } this.validators.forEach(function (v) { if (err) { return; } var validator = v.validator; var validatorProperties = utils.clone(v); validatorProperties.path = path; validatorProperties.value = value; if (validator instanceof RegExp) { validate(validator.test(value), validatorProperties); } else if ('function' === typeof validator) { // if not async validators if (2 !== validator.length) { validate(validator.call(scope, value), validatorProperties); } } }); return err; };SchemaType#get(
fn)Adds a getter to this schematype.
Parameters:
fn<Function>
Returns:
- <SchemaType> <p>this</p>
show codeExample:
function dob (val) { if (!val) return val; return (val.getMonth() + 1) + "/" + val.getDate() + "/" + val.getFullYear(); } // defining within the schema var s = new Schema({ born: { type: Date, get: dob }) // or by retreiving its SchemaType var s = new Schema({ born: Date }) s.path('born').get(dob)Getters allow you to transform the representation of the data as it travels from the raw mongodb document to the value that you see.
Suppose you are storing credit card numbers and you want to hide everything except the last 4 digits to the mongoose user. You can do so by defining a getter in the following way:
function obfuscate (cc) { return '****-****-****-' + cc.slice(cc.length-4, cc.length); } var AccountSchema = new Schema({ creditCardNumber: { type: String, get: obfuscate } }); var Account = db.model('Account', AccountSchema); Account.findById(id, function (err, found) { console.log(found.creditCardNumber); // '****-****-****-1234' });Getters are also passed a second argument, the schematype on which the getter was defined. This allows for tailored behavior based on options passed in the schema.
function inspector (val, schematype) { if (schematype.options.required) { return schematype.path + ' is required'; } else { return schematype.path + ' is not'; } } var VirusSchema = new Schema({ name: { type: String, required: true, get: inspector }, taxonomy: { type: String, get: inspector } }) var Virus = db.model('Virus', VirusSchema); Virus.findById(id, function (err, virus) { console.log(virus.name); // name is required console.log(virus.taxonomy); // taxonomy is not })SchemaType.prototype.get = function (fn) { if ('function' !== typeof fn) throw new TypeError('A getter must be a function.'); this.getters.push(fn); return this; };SchemaType#getDefault(
scope,init)Gets the default value
show codeSchemaType.prototype.getDefault = function (scope, init) { var ret = 'function' === typeof this.defaultValue ? this.defaultValue.call(scope) : this.defaultValue; if (null !== ret && undefined !== ret) { return this.cast(ret, scope, init); } else { return ret; } };SchemaType#required(
required,[message])Adds a required validator to this schematype.
Parameters:
Returns:
- <SchemaType> <p>this</p>
show codeExample:
var s = new Schema({ born: { type: Date, required: true }) // or with custom error message var s = new Schema({ born: { type: Date, required: '{PATH} is required!' }) // or through the path API Schema.path('name').required(true); // with custom error messaging Schema.path('name').required(true, 'grrr :( ');SchemaType.prototype.required = function (required, message) { if (false === required) { this.validators = this.validators.filter(function (v) { return v.validator != this.requiredValidator; }, this); this.isRequired = false; return this; } var self = 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 (this !== undefined && // специальная проверка из-за strict mode и особенности .call(undefined) 'isSelected' in this && !this.isSelected(self.path) && !this.isModified(self.path)) return true; return (('function' === typeof required) && !required.apply(this)) || self.checkRequired(v, this); }; if ('string' === typeof required) { message = required; required = undefined; } var msg = message || errorMessages.general.required; this.validators.push({ validator: this.requiredValidator, message: msg, type: 'required' }); return this; };SchemaType(
path,[options],[instance])SchemaType constructor
show codefunction SchemaType (path, options, instance) { this.path = path; this.instance = instance; this.validators = []; this.setters = []; this.getters = []; this.options = options; for (var i in options) if (this[i] && 'function' === typeof this[i]) { var opts = Array.isArray(options[i]) ? options[i] : [options[i]]; this[i].apply(this, opts); } }SchemaType#set(
fn)Adds a setter to this schematype.
Parameters:
fn<Function>
Returns:
- <SchemaType> <p>this</p>
show codeExample:
function capitalize (val) { if ('string' != typeof val) val = ''; return val.charAt(0).toUpperCase() + val.substring(1); } // defining within the schema var s = new Schema({ name: { type: String, set: capitalize }}) // or by retreiving its SchemaType var s = new Schema({ name: String }) s.path('name').set(capitalize)Setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key.
Suppose you are implementing user registration for a website. Users provide an email and password, which gets saved to mongodb. The email is a string that you will want to normalize to lower case, in order to avoid one email having more than one account -- e.g., otherwise, avenue@q.com can be registered for 2 accounts via avenue@q.com and AvEnUe@Q.CoM.
You can set up email lower case normalization easily via a Storage setter.
function toLower (v) { return v.toLowerCase(); } var UserSchema = new Schema({ email: { type: String, set: toLower } }) var User = db.model('User', UserSchema) var user = new User({email: 'AVENUE@Q.COM'}) console.log(user.email); // 'avenue@q.com' // or var user = new User user.email = 'Avenue@Q.com' console.log(user.email) // 'avenue@q.com'As you can see above, setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key.
NOTE: we could have also just used the built-in
lowercase: trueSchemaType option instead of defining our own function.new Schema({ email: { type: String, lowercase: true }})Setters are also passed a second argument, the schematype on which the setter was defined. This allows for tailored behavior based on options passed in the schema.
function inspector (val, schematype) { if (schematype.options.required) { return schematype.path + ' is required'; } else { return val; } } var VirusSchema = new Schema({ name: { type: String, required: true, set: inspector }, taxonomy: { type: String, set: inspector } }) var Virus = db.model('Virus', VirusSchema); var v = new Virus({ name: 'Parvoviridae', taxonomy: 'Parvovirinae' }); console.log(v.name); // name is required console.log(v.taxonomy); // ParvovirinaeSchemaType.prototype.set = function (fn) { if ('function' !== typeof fn) throw new TypeError('A setter must be a function.'); this.setters.push(fn); return this; };SchemaType#validate(
obj,[message])Adds validator(s) for this document path.
Parameters:
Returns:
- <SchemaType> <p>this</p>
show codeValidators always receive the value to validate as their first argument and must return
Boolean. Returningfalsemeans validation failed.The error message argument is optional. If not passed, the default generic error message template will be used.
Examples:
// make sure every value is equal to "something" function validator (val) { return val == 'something'; } new Schema({ name: { type: String, validate: validator }}); // with a custom error message var custom = [validator, 'Uh oh, {PATH} does not equal "something".'] new Schema({ name: { type: String, validate: custom }}); // adding many validators at a time var many = [ { validator: validator, msg: 'uh oh' } , { validator: anotherValidator, msg: 'failed' } ] new Schema({ name: { type: String, validate: many }}); // or utilizing SchemaType methods directly: var schema = new Schema({ name: 'string' }); schema.path('name').validate(validator, 'validation of `{PATH}` failed with value `{VALUE}`');Error message templates:
From the examples above, you may have noticed that error messages support baseic templating. There are a few other template keywords besides
{PATH}and{VALUE}too. To find out more, details are available hereAsynchronous validation:
Passing a validator function that receives two arguments tells mongoose that the validator is an asynchronous validator. The first argument passed to the validator function is the value being validated. The second argument is a callback function that must called when you finish validating the value and passed either
trueorfalseto communicate either success or failure respectively.schema.path('name').validate(function (value, respond) { doStuff(value, function () { ... respond(false); // validation failed }) }, '{PATH} failed validation.');You might use asynchronous validators to retreive other documents from the database to validate against or to meet other I/O bound validation needs.
Validation occurs
pre('save')or whenever you manually execute document#validate.If validation fails during
pre('save')and no callback was passed to receive the error, anerrorevent will be emitted on your Models associated db connection, passing the validation error object along.var conn = mongoose.createConnection(..); conn.on('error', handleError); var Product = conn.model('Product', yourSchema); var dvd = new Product(..); dvd.save(); // emits error on the `conn` aboveIf you desire handling these errors at the Model level, attach an
errorlistener to your Model and the event will instead be emitted there.// registering an error listener on the Model lets us handle errors more locally Product.on('error', handleError);SchemaType.prototype.validate = function (obj, message, type) { if ('function' == typeof obj || obj && 'RegExp' === utils.getFunctionName(obj.constructor)) { var properties; if (message instanceof Object && !type) { properties = utils.clone(message); if (!properties.message) { properties.message = properties.msg; } properties.validator = obj; } else { if (!message) message = errorMessages.general.default; if (!type) type = 'user defined'; properties = { message: message, type: type, validator: obj }; } this.validators.push(properties); return this; } var i; var length; var arg; for (i=0, length=arguments.length; i<length; i++) { arg = arguments[i]; if (!(arg && 'Object' === utils.getFunctionName(arg.constructor) )) { 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; };SchemaType._isRef(
self,value)Determines if value is a valid Reference.
show codeSchemaType._isRef = function( self, value ){ // fast path var ref = self.options && self.options.ref; if ( ref ) { if ( null == value ) return true; if ( _.isObject( value ) ) { return true; } } return false; }; //exports module.exports = SchemaType; SchemaType.CastError = CastError; SchemaType.ValidatorError = ValidatorError;Parameters:
self<SchemaType>value<Object>
Returns:
- <Boolean>
На клиенте в качестве ссылки можно хранить как id, так и полные документы
- types/array.js
function Object() { [native code] }#_cast(
value)Casts a member based on this arrays schema.
Parameters:
value
show codeReturns:
- <> <p>value the casted value</p>
_cast: function ( value ) { var owner = this._owner; var populated = false; if (this._parent) { // if a populated array, we must cast to the same model // instance as specified in the original query. if (!owner) { owner = this._owner = this._parent.ownerDocument ? this._parent.ownerDocument() : this._parent; } populated = owner.populated(this._path, true); } if (populated && null != value) { // cast to the populated Models schema var Model = populated.options.model; // only objects are permitted so we can safely assume that // non-objects are to be interpreted as _id if ( value instanceof ObjectId || !_.isObject(value) ) { value = { _id: value }; } // gh-2399 // we should cast model only when it's not a discriminator var isDisc = value.schema && value.schema.discriminatorMapping && value.schema.discriminatorMapping.key !== undefined; if (!isDisc) { value = new Model(value); } return this._schema.caster.cast(value, this._parent, true); } return this._schema.caster.cast(value, this._parent, false); },function Object() { [native code] }#_markModified(
embeddedDoc,embeddedPath)Marks this array as modified.
Parameters:
embeddedDoc<EmbeddedDocument> <p>the embedded doc that invoked this method on the Array</p>embeddedPath<String> <p>the path which changed in the embeddedDoc</p>
show codeIf it bubbles up from an embedded document change, then it takes the following arguments (otherwise, takes 0 arguments)
_markModified: function (elem, embeddedPath) { var parent = this._parent , dirtyPath; if (parent) { dirtyPath = this._path; if (arguments.length) { if (null != embeddedPath) { // an embedded doc bubbled up the change dirtyPath = dirtyPath + '.' + this.indexOf(elem) + '.' + embeddedPath; } else { // directly set an index dirtyPath = dirtyPath + '.' + elem; } } parent.markModified(dirtyPath); } return this; },function Object() { [native code] }#addToSet(
arguments)Adds values to the array if not already present.
Parameters:
arguments
Returns:
- <Array> <p>the values that were added</p>
show codeExample:
console.log(doc.array) // [2,3,4] var added = doc.array.addToSet(4,5); console.log(doc.array) // [2,3,4,5] console.log(added) // [5]addToSet: function addToSet () { var values = [].map.call(arguments, this._cast, this) , added = [] , type = values[0] instanceof EmbeddedDocument ? 'doc' : values[0] instanceof Date ? 'date' : ''; values.forEach(function (v) { var found; switch (type) { case 'doc': found = this.some(function(doc){ return doc.equals(v); }); break; case 'date': var val = +v; found = this.some(function(d){ return +d === val; }); break; default: found = ~this.indexOf(v); } if (!found) { [].push.call(this, v); this._markModified(); [].push.call(added, v); } }, this); return added; },function Object() { [native code] }#indexOf(
obj)Return the index of
objor-1if not found.Parameters:
obj<Object> <p>the item to look for</p>
show codeReturns:
- <Number>
indexOf: function indexOf (obj) { if (obj instanceof ObjectId) obj = obj.toString(); for (var i = 0, len = this.length; i < len; ++i) { if (obj == this[i]) return i; } return -1; } };function Object() { [native code] }#pop()
Wraps
Array#popwith proper change tracking.show codeNote:
marks the entire array as modified which will pass the entire thing to $set potentially overwritting any changes that happen between when you retrieved the object and when you save it.
pop: function () { var ret = [].pop.call(this); this._markModified(); return ret; },function Object() { [native code] }#pull(
arguments)Pulls items from the array atomically.
Parameters:
arguments
See:
show codeExamples:
doc.array.pull(ObjectId) doc.array.pull({ _id: 'someId' }) doc.array.pull(36) doc.array.pull('tag 1', 'tag 2')To remove a document from a subdocument array we may pass an object with a matching
_id.doc.subdocs.push({ _id: 4815162342 }) doc.subdocs.pull({ _id: 4815162342 }) // removedOr we may passing the _id directly and let storage take care of it.
doc.subdocs.push({ _id: 4815162342 }) doc.subdocs.pull(4815162342); // workspull: function () { var values = [].map.call(arguments, this._cast, this) , cur = this._parent.get(this._path) , i = cur.length , mem; while (i--) { mem = cur[i]; if (mem instanceof EmbeddedDocument) { if (values.some(function (v) { return v.equals(mem); } )) { [].splice.call(cur, i, 1); } } else if (~cur.indexOf.call(values, mem)) { [].splice.call(cur, i, 1); } } this._markModified(); return this; },function Object() { [native code] }#push(
[args...])Wraps
Array#pushwith proper change tracking.show codeParameters:
[args...]<Object>
push: function () { var values = [].map.call(arguments, this._cast, this) , ret = [].push.apply(this, values); this._markModified(); return ret; },function Object() { [native code] }#set()
Sets the casted
valat indexiand marks the array modified.Returns:
- <Array> <p>this</p>
show codeExample:
// given documents based on the following var docs = storage.createCollection('Doc', new Schema({ array: [Number] })); var doc = docs.add({ array: [2,3,4] }) console.log(doc.array) // [2,3,4] doc.array.set(1,"5"); console.log(doc.array); // [2,5,4] // properly cast to number doc.save() // the change is saved // VS not using array#set doc.array[1] = "5"; console.log(doc.array); // [2,"5",4] // no casting doc.save() // change is not savedset: function (i, val) { this[i] = this._cast(val); this._markModified(i); return this; },function Object() { [native code] }#shift()
Wraps
Array#shiftwith proper change tracking.show codeExample:
doc.array = [2,3]; var res = doc.array.shift(); console.log(res) // 2 console.log(doc.array) // [3]Note:
marks the entire array as modified, which if saved, will store it as a
$setoperation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.shift: function () { var ret = [].shift.call(this); this._markModified(); return ret; },function Object() { [native code] }#sort()
Wraps
Array#sortwith proper change tracking.show codeNOTE:
marks the entire array as modified, which if saved, will store it as a
$setoperation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.sort: function () { var ret = [].sort.apply(this, arguments); this._markModified(); return ret; },function Object() { [native code] }#splice()
Wraps
Array#splicewith proper change tracking and casting.show codeNote:
marks the entire array as modified, which if saved, will store it as a
$setoperation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.splice: function splice () { var ret, vals, i; if (arguments.length) { vals = []; for (i = 0; i < arguments.length; ++i) { vals[i] = i < 2 ? arguments[i] : this._cast(arguments[i]); } ret = [].splice.apply(this, vals); this._markModified(); } return ret; },StorageArray(
values,path,doc)Storage Array constructor.
Inherits:
show codeNOTE:
Values always have to be passed to the constructor to initialize, otherwise
StorageArray#pushwill mark the array as modified.function StorageArray (values, path, doc) { var arr = [].concat(values); _.mixin( arr, StorageArray.mixin ); arr.validators = []; arr._path = path; arr.isStorageArray = true; if (doc) { arr._parent = doc; arr._schema = doc.schema.path(path); } return arr; } StorageArray.mixin = {function Object() { [native code] }#toObject(
options)Returns a native js Array.
Parameters:
options<Object>
show codeReturns:
- <Array>
toObject: function (options) { if (options && options.depopulate) { return this.map(function (doc) { return doc instanceof Document ? doc.toObject(options) : doc; }); } return this.slice(); },function Object() { [native code] }#unshift()
Wraps
Array#unshiftwith proper change tracking.show codeNote:
marks the entire array as modified, which if saved, will store it as a
$setoperation, potentially overwritting any changes that happen between when you retrieved the object and when you save it.unshift: function () { var values = [].map.call(arguments, this._cast, this); [].unshift.apply(this, values); this._markModified(); return this.length; },StorageArray.mixin.remove()
Alias of pull
See:
= see.url || see.local StorageArray#pull= see.url || see.local mongodb
- types/buffer.js
function Object() { [native code] }#_markModified()
Marks this buffer as modified.
show code_markModified: function () { var parent = this._parent; if (parent) { parent.markModified(this._path); } return this; },function Object() { [native code] }#copy(
target)Copies the buffer.
Parameters:
target<Buffer>
Returns:
show codeNote:
Buffer#copydoes not marktargetas modified so you must copy from aStorageBufferfor it to work as expected. This is a work around sincecopymodifies the target, not this.copy: function (target) { var ret = Buffer.prototype.copy.apply(this, arguments); if (target && target.isStorageBuffer) { target._markModified(); } return ret; } };StorageBuffer(
value,encode,offset)Storage Buffer constructor.
Inherits:
show codeValues always have to be passed to the constructor to initialize.
function StorageBuffer (value, encode, offset) { var length = arguments.length; var val; if (0 === length || null === arguments[0] || undefined === arguments[0]) { val = 0; } else { val = value; } var encoding; var path; var doc; if (Array.isArray(encode)) { // internal casting path = encode[0]; doc = encode[1]; } else { encoding = encode; } var buf = new Buffer(val, encoding, offset); _.mixin( buf, StorageBuffer.mixin ); buf.isStorageBuffer = true; // make sure these internal props don't show up in Object.keys() Object.defineProperties(buf, { validators: { value: [] } , _path: { value: path } , _parent: { value: doc } }); if (doc && 'string' === typeof path) { Object.defineProperty(buf, '_schema', { value: doc.schema.path(path) }); } buf._subtype = 0; return buf; }function Object() { [native code] }#write()
Writes the buffer.
show codewrite: function () { var written = Buffer.prototype.write.apply(this, arguments); if (written > 0) { this._markModified(); } return written; },StorageBuffer.mixin.equals(
other)Determines if this buffer is equals to
show codeotherbufferStorageBuffer.mixin.equals = function (other) { if (!Buffer.isBuffer(other)) { return false; } if (this.length !== other.length) { return false; } for (var i = 0; i < this.length; ++i) { if (this[i] !== other[i]) return false; } return true; };Parameters:
other<Buffer>
Returns:
- <Boolean>
StorageBuffer.mixin.subtype(
subtype)Sets the subtype option and marks the buffer modified.
show codeStorageBuffer.mixin.subtype = function (subtype) { if ('number' !== typeof subtype) { throw new TypeError('Invalid subtype. Expected a number'); } if (this._subtype !== subtype) { this._markModified(); } this._subtype = subtype; };Parameters:
subtype<Hex>
See:
= see.url || see.local http://bsonspec.org/#/specification
SubTypes:
var bson = require('bson')
bson.BSON_BINARY_SUBTYPE_DEFAULT
bson.BSON_BINARY_SUBTYPE_FUNCTION
bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
bson.BSON_BINARY_SUBTYPE_UUID
bson.BSON_BINARY_SUBTYPE_MD5
bson.BSON_BINARY_SUBTYPE_USER_DEFINEDdoc.buffer.subtype(bson.BSON_BINARY_SUBTYPE_UUID);
StorageBuffer.mixin.toObject(
[subtype])Converts this buffer to its Binary type representation.
show codeStorageBuffer.mixin.toObject = function (options) { var subtype = 'number' === typeof options ? options : (this._subtype || 0); return new Binary(this, subtype); };Parameters:
[subtype]<Hex>
Returns:
- <Binary>
See:
= see.url || see.local http://bsonspec.org/#/specification
SubTypes:
var bson = require('bson')
bson.BSON_BINARY_SUBTYPE_DEFAULT
bson.BSON_BINARY_SUBTYPE_FUNCTION
bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
bson.BSON_BINARY_SUBTYPE_UUID
bson.BSON_BINARY_SUBTYPE_MD5
bson.BSON_BINARY_SUBTYPE_USER_DEFINEDdoc.buffer.toObject(bson.BSON_BINARY_SUBTYPE_USER_DEFINED);
function Object() { [native code] }#_subtype
Default subtype for the Binary representing this Buffer
show code_subtype: undefined, - types/documentarray.js
StorageDocumentArray(
values,path,doc)DocumentArray constructor
Parameters:
Returns:
show codeInherits:
function StorageDocumentArray (values, path, doc) { // Values always have to be passed to the constructor to initialize, since // otherwise MongooseArray#push will mark the array as modified to the parent. var arr = [].concat(values); _.mixin( arr, StorageDocumentArray.mixin ); arr.validators = []; arr._path = path; arr.isStorageArray = true; arr.isStorageDocumentArray = true; if (doc) { arr._parent = doc; arr._schema = doc.schema.path(path); arr._handlers = { isNew: arr.notify('isNew'), save: arr.notify('save') }; // Проброс изменения состояния в поддокумент doc.on('save', arr._handlers.save); doc.on('isNew', arr._handlers.isNew); } return arr; }StorageDocumentArray.mixin._cast()
Overrides StorageArray#cast
show codeStorageDocumentArray.mixin._cast = function (value) { if (value instanceof this._schema.casterConstructor) { if (!(value.__parent && value.__parentArray)) { // value may have been created using array.create() value.__parent = this._parent; value.__parentArray = this; } return value; } // handle cast('string') or cast(ObjectId) etc. // only objects are permitted so we can safely assume that // non-objects are to be interpreted as _id if ( value instanceof ObjectId || !_.isObject(value) ) { value = { _id: value }; } return new this._schema.casterConstructor(value, this); };StorageDocumentArray.mixin.create(
obj)Creates a subdocument casted to this schema.
show codeStorageDocumentArray.mixin.create = function (obj) { return new this._schema.casterConstructor(obj); };Parameters:
obj<Object> <p>the value to cast to this arrays SubDocument schema</p>
This is the same subdocument constructor used for casting.
StorageDocumentArray.mixin.id(
id)Searches array items for the first document with a matching _id.
show codeStorageDocumentArray.mixin.id = function (id) { var casted , sid , _id; try { var casted_ = ObjectIdSchema.prototype.cast.call({}, id); if (casted_) casted = String(casted_); } catch (e) { casted = null; } for (var i = 0, l = this.length; i < l; i++) { _id = this[i].get('_id'); if (_id instanceof Document) { sid || (sid = String(id)); if (sid == _id._id) return this[i]; } else if (!(_id instanceof ObjectId)) { sid || (sid = String(id)); if (sid == _id) return this[i]; } else if (casted == _id) { return this[i]; } } return null; };Returns:
- <EmbeddedDocument> <p>the subdocument or null if not found.</p>
Example:
var embeddedDoc = m.array.id(some_id);StorageDocumentArray.mixin.notify(
event)Creates a fn that notifies all child docs of
show codeevent.StorageDocumentArray.mixin.notify = function notify (event) { var self = this; return function notify (val) { var i = self.length; while (i--) { if (!self[i]) continue; self[i].trigger(event, val); } }; };Parameters:
event<String>
Returns:
- <Function>
StorageDocumentArray.mixin.toObject(
[options])Returns a native js Array of plain js objects
show codeStorageDocumentArray.mixin.toObject = function (options) { return this.map(function (doc) { return doc && doc.toObject(options) || null; }); };Parameters:
[options]<Object> <p>optional options to pass to each documents <code>toObject</code> method call during conversion</p>
Returns:
- <Array>
NOTE:
Each sub-document is converted to a plain object by calling its
#toObjectmethod. - types/embedded.js
EmbeddedDocument#$__fullPath(
[path])Returns the full path to this document. If optional
pathis passed, it is appended to the full path.Parameters:
[path]<String>
Returns:
- <String>
EmbeddedDocument(
data,parentArr)EmbeddedDocument constructor.
Parameters:
data<Object> <p>js object returned from the db</p>parentArr<StorageDocumentArray> <p>the parent array of this document</p>
show codeInherits:
function EmbeddedDocument ( data, parentArr ) { if (parentArr) { this.__parentArray = parentArr; this.__parent = parentArr._parent; } else { this.__parentArray = undefined; this.__parent = undefined; } Document.call( this, data, undefined ); // Нужно для проброса изменения значения из родительского документа, например при сохранении var self = this; this.on('isNew', function (val) { self.isNew = val; }); }EmbeddedDocument#invalidate(
path,err)Marks a path as invalid, causing validation to fail.
Parameters:
show codeReturns:
- <Boolean>
EmbeddedDocument.prototype.invalidate = function (path, err, val, first) { if (!this.__parent) { var msg = 'Unable to invalidate a subdocument that has not been added to an array.'; throw new Error(msg); } var index = this.__parentArray.indexOf(this); var parentPath = this.__parentArray._path; var fullPath = [parentPath, index, path].join('.'); // sniffing arguments: // need to check if user passed a value to keep // our error message clean. if (2 < arguments.length) { this.__parent.invalidate(fullPath, err, val); } else { this.__parent.invalidate(fullPath, err); } if (first) this.$__.validationError = this.ownerDocument().$__.validationError; return true; };EmbeddedDocument#markModified(
path)Marks the embedded doc modified.
Parameters:
path<String> <p>the path which changed</p>
show codeExample:
var doc = blogpost.comments.id(hexstring); doc.mixed.type = 'changed'; doc.markModified('mixed.type');EmbeddedDocument.prototype.markModified = function (path) { if (!this.__parentArray) return; this.$__.activePaths.modify(path); if (this.isNew) { // Mark the WHOLE parent array as modified // if this is a new document (i.e., we are initializing // a document), this.__parentArray._markModified(); } else this.__parentArray._markModified(this, path); };EmbeddedDocument#ownerDocument()
Returns the top level document of this sub-document.
show codeReturns:
- <Document>
EmbeddedDocument.prototype.ownerDocument = function () { if (this.$__.ownerDocument) { return this.$__.ownerDocument; } var parent = this.__parent; if (!parent) return this; while (parent.__parent) { parent = parent.__parent; } this.$__.ownerDocument = parent; return this.$__.ownerDocument; };EmbeddedDocument#parent()
Returns this sub-documents parent document.
show codeEmbeddedDocument.prototype.parent = function () { return this.__parent; };EmbeddedDocument#parentArray()
Returns this sub-documents parent array.
show codeEmbeddedDocument.prototype.parentArray = function () { return this.__parentArray; };EmbeddedDocument#remove(
[fn])Removes the subdocument from its parent array.
show codeParameters:
[fn]<Function>
EmbeddedDocument.prototype.remove = function (fn) { if (!this.__parentArray) return this; var _id; if (!this.willRemove) { _id = this._doc._id; if (!_id) { throw new Error('For your own good, Storage does not know ' + 'how to remove an EmbeddedDocument that has no _id'); } this.__parentArray.pull({ _id: _id }); this.willRemove = true; } if (fn) fn(null); return this; };EmbeddedDocument#save(
[fn])Used as a stub for hooks.js
Parameters:
[fn]<Function>
Returns:
- <Promise> <p>resolved Promise</p>
show codeNOTE:
This is a no-op. Does not actually save the doc to the db.
EmbeddedDocument.prototype.save = function (fn) { var promise = new Deferred().done(fn); promise.resolve(); return promise; };EmbeddedDocument#update()
Override #update method of parent documents.
show codeEmbeddedDocument.prototype.update = function () { throw new Error('The #update method is not available on EmbeddedDocuments'); }; - types/objectid.js
ObjectId#equals(
otherID)Compares the equality of this ObjectId with
otherID.Parameters:
otherID<object> <p>ObjectId instance to compare against.</p>
Returns:
- <boolean> <p>the result of comparing two ObjectId's</p>
ObjectId#generate(
[time])Generate a 12 byte id string used in ObjectId's
Parameters:
[time]<number> <p>optional parameter allowing to pass in a second based timestamp.</p>
Returns:
- <string> <p>return the 12 byte id binary string.</p>
ObjectId#get_inc()
Update the ObjectId index used in generating new ObjectId's on the driver
Returns:
- <number> <p>returns next index value.</p>
ObjectId#getInc()
Update the ObjectId index used in generating new ObjectId's on the driver
Returns:
- <number> <p>returns next index value.</p>
ObjectId#getTimestamp()
Returns the generation date (accurate up to the second) that this ID was generated.
Returns:
- <date> <p>the generation date</p>
()
Machine id.
show codeCreate a random 3-byte value (i.e. unique for this
process). Other drivers use a md5 of the machine id here, but
that would mean an asyc call to gethostname, so we don't bother.var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10); // Regular expression that checks for hex value var checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$');()
for time-based ObjectId the bytes following the time will be zeroed
show codevar machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false); var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid); var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true); return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes; };ObjectId#toHexString()
Return the ObjectId id as a 24 byte hex string representation
Returns:
- <string> <p>return the 24 byte hex string representation.</p>
ObjectId#toJSON()
Converts to its JSON representation.
show codeReturns:
- <String> <p>return the 24 byte hex string representation.</p>
ObjectId.prototype.toJSON = function() { return this.toHexString(); };ObjectId#toString()
Converts the id into a 24 byte hex string for printing
show codeReturns:
- <String> <p>return the 24 byte hex string representation.</p>
ObjectId.prototype.toString = function() { return this.toHexString(); };ObjectId.createFromHexString(
hexString)Creates an ObjectId from a hex string representation of an ObjectId.
Parameters:
hexString<string> <p>create a ObjectId from a passed in 24 byte hexstring.</p>
Returns:
- <ObjectId> <p>return the created ObjectId</p>
ObjectId.createFromTime(
time)Creates an ObjectId from a second based number, with the rest of the ObjectId zeroed out. Used for comparisons or sorting the ObjectId.
Parameters:
time<number> <p>an integer number representing a number of seconds.</p>
Returns:
- <ObjectId> <p>return the created ObjectId</p>
ObjectId.isValid()
Checks if a value is a valid bson ObjectId
Returns:
- <boolean> <p>return true if the value is a valid bson ObjectId, return false otherwise.</p>
ObjectId#ObjectId
Create a new ObjectId instance
show codefunction ObjectId(id) { if(!(this instanceof ObjectId)) return new ObjectId(id); if((id instanceof ObjectId)) return id; this._bsontype = 'ObjectId'; var valid = ObjectId.isValid(id); // Throw an error if it's not a valid setup if(!valid && id != null){ throw new Error('Argument passed in must be a single String of 12 bytes or a string of 24 hex characters'); } else if(valid && typeof id === 'string' && id.length === 24) { return ObjectId.createFromHexString(id); } else if(id == null || typeof id === 'number') { // convert to 12 byte binary string this.id = this.generate(id); } else if(id != null && id.length === 12) { // assume 12 byte string this.id = id; } if(ObjectId.cacheHexString) this.__id = this.toHexString(); } // Precomputed hex table enables speedy hex string conversion var hexTable = []; for (var i = 0; i < 256; i++) { hexTable[i] = (i <= 15 ? '0' : '') + i.toString(16); }Returns:
- <ObjectId> <p>instance of ObjectId.</p>
- utils.js
exports.pluralization
Pluralization rules.
show codeexports.pluralization = [ [/(m)an$/gi, '$1en'], [/(pe)rson$/gi, '$1ople'], [/(child)$/gi, '$1ren'], [/^(ox)$/gi, '$1en'], [/(ax|test)is$/gi, '$1es'], [/(octop|vir)us$/gi, '$1i'], [/(alias|status)$/gi, '$1es'], [/(bu)s$/gi, '$1ses'], [/(buffal|tomat|potat)o$/gi, '$1oes'], [/([ti])um$/gi, '$1a'], [/sis$/gi, 'ses'], [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'], [/(hive)$/gi, '$1s'], [/([^aeiouy]|qu)y$/gi, '$1ies'], [/(x|ch|ss|sh)$/gi, '$1es'], [/(matr|vert|ind)ix|ex$/gi, '$1ices'], [/([m|l])ouse$/gi, '$1ice'], [/(kn|w|l)ife$/gi, '$1ives'], [/(quiz)$/gi, '$1zes'], [/s$/gi, 's'], [/([^a-z])$/, '$1'], [/$/gi, 's'] ]; var rules = exports.pluralization;These rules are applied while processing the argument to
pluralize.exports.uncountables
Uncountable words.
show codeexports.uncountables = [ 'advice', 'energy', 'excretion', 'digestion', 'cooperation', 'health', 'justice', 'labour', 'machinery', 'equipment', 'information', 'pollution', 'sewage', 'paper', 'money', 'species', 'series', 'rain', 'rice', 'fish', 'sheep', 'moose', 'deer', 'news', 'expertise', 'status', 'media' ]; var uncountables = exports.uncountables;These words are applied while processing the argument to
pluralize. - virtualtype.js
VirtualType#applyGetters(
value,scope)Applies getters to
valueusing optionalscope.show codeReturns:
- <> <p>the value after applying all getters</p>
VirtualType.prototype.applyGetters = function (value, scope) { var v = value; for (var l = this.getters.length - 1; l >= 0; l--) { v = this.getters[l].call(scope, v, this); } return v; };VirtualType#applySetters(
value,scope)Applies setters to
valueusing optionalscope.show codeReturns:
- <> <p>the value after applying all setters</p>
VirtualType.prototype.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; };VirtualType#get(
fn)Defines a getter.
Parameters:
fn<Function>
Returns:
- <VirtualType> <p>this</p>
show codeExample:
var virtual = schema.virtual('fullname'); virtual.get(function () { return this.name.first + ' ' + this.name.last; });VirtualType.prototype.get = function (fn) { this.getters.push(fn); return this; };VirtualType#set(
fn)Defines a setter.
Parameters:
fn<Function>
Returns:
- <VirtualType> <p>this</p>
show codeExample:
var virtual = schema.virtual('fullname'); virtual.set(function (v) { var parts = v.split(' '); this.name.first = parts[0]; this.name.last = parts[1]; });VirtualType.prototype.set = function (fn) { this.setters.push(fn); return this; };VirtualType()
VirtualType constructor
show codeThis is what mongoose uses to define virtual attributes via
Schema.prototype.virtual.Example:
var fullname = schema.virtual('fullname'); fullname instanceof mongoose.VirtualType // truefunction VirtualType (options, name) { this.path = name; this.getters = []; this.setters = []; this.options = options || {}; } - collection.js
function Object() { [native code] }#add(
[doc],[fields],[init],[_storageWillMutate])To add document or array of documents.
show codeParameters:
[doc]<object, Array.> <ul> <li>doc object or array of doc objects</li> </ul>[fields]<object> <ul> <li>selected fields in the query from the server (not implemented in Document)</li> </ul>[init]<boolean> <ul> <li>hydrate document - наполнить документ данными (используется в api-client)</li> </ul>[_storageWillMutate]<boolean> <ul> <li>Флаг добавления массива документов. только для внутреннего использования</li> </ul>
add: function( doc, fields, init, _storageWillMutate ){ var self = this; // Если документа нет, значит будет пустой if ( doc == null ) doc = null; // Массив документов if ( _.isArray( doc ) ){ var savedDocs = []; _.each( doc, function( doc ){ savedDocs.push( self.add( doc, fields, init, true ) ); }); this.storageHasMutated(); return savedDocs; } var id = doc && doc._id; // Если документ уже есть, то просто установить значения if ( id && this.documents[ id ] ){ this.documents[ id ].set( doc ); } else { var discriminatorMapping = this.schema ? this.schema.discriminatorMapping : null; var key = discriminatorMapping && discriminatorMapping.isRoot ? discriminatorMapping.key : null; // Выбираем схему, если есть дискриминатор var schema; if (key && doc && doc[key] && this.schema.discriminators && this.schema.discriminators[doc[key]]) { schema = this.schema.discriminators[doc[key]]; } else { schema = this.schema; } var newDoc = new Document( doc, this.name, schema, fields, init ); //todo: тут нужна проверка на существование id (может стоит смотреть в схеме опцию id)function Object() { [native code] }#find(
conditions)Find documents by conditions.
show codeParameters:
conditions
find: function( conditions ){ return _.where( this.documents, conditions ); },function Object() { [native code] }#findById(
_id)Find document by id.
show codeParameters:
_id
findById: function( _id ){ return this.documents[ _id ]; },function Object() { [native code] }#findByIdAndRemove(
_id)Find document by id and remove it.
show codeParameters:
_id
findByIdAndRemove: function( _id ){ this.remove( this.findById( _id ) ); return this; },function Object() { [native code] }#findByIdAndUpdate(
_id,path,value)Find document by id and update the path value in it.
show codefindByIdAndUpdate: function( _id, path, value ){ return this.update( this.findById( _id ), path, value ); },function Object() { [native code] }#findOne(
conditions)Find one document by conditions.
show codeParameters:
conditions
findOne: function( conditions ){ return _.findWhere( this.documents, conditions ); },function Object() { [native code] }#findOneAndRemove(
conditions)Find one document by conditions and remove it.
show codeParameters:
conditions<object>
findOneAndRemove: function( conditions ){ this.remove( this.findOne( conditions ) ); return this; },function Object() { [native code] }#findOneAndUpdate(
conditions,path,value)Find one document by conditions and update the path value in it.
show codefindOneAndUpdate: function( conditions, path, value ){ return this.update( this.findOne( conditions ), path, value ); },function Object() { [native code] }#remove(
document)Remove document.
show coderemove: function( document ){ return delete this.documents[ document._id || document ]; },function Object() { [native code] }#storageHasMutated()
Обработчик на изменения (добавление, удаление) данных в коллекции
show codestorageHasMutated: function(){ // Обновим массив документов (специальное отображение для перебора нокаутом) this.array = _.toArray( this.documents ); },function Object() { [native code] }#update(
document,path,value)Update the path value in the document.
show codeupdate: function( document, path, value ){ var doc = this.documents[ document._id || document ]; if ( doc == null ){ console.warn('storage::update: Document is not found.'); return false; } return doc.set( path, value ); },function Object() { [native code] }#updateIdLink(
doc)Обновить ссылку на документ в поле documents
show codeParameters:
doc<Document>
updateIdLink: function( doc ){ var id = doc._id.toString(); var oldId = _.findKey( this.documents, { _id: doc._id }); if ( !oldId ){ throw new TypeError('Не найден документ для обновления ссылки по этому _id: ' + id ); } delete this.documents[ oldId ]; this.documents[ id ] = doc; } };
