index.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. 'use strict';
  2. /*!
  3. * Module dependencies.
  4. */
  5. if (global.MONGOOSE_DRIVER_PATH) {
  6. const deprecationWarning = 'The `MONGOOSE_DRIVER_PATH` global property is ' +
  7. 'deprecated. Use `mongoose.driver.set()` instead.';
  8. const setDriver = require('util').deprecate(function() {
  9. require('./driver').set(require(global.MONGOOSE_DRIVER_PATH));
  10. }, deprecationWarning);
  11. setDriver();
  12. } else {
  13. require('./driver').set(require('./drivers/node-mongodb-native'));
  14. }
  15. const Schema = require('./schema');
  16. const SchemaType = require('./schematype');
  17. const SchemaTypes = require('./schema/index');
  18. const VirtualType = require('./virtualtype');
  19. const STATES = require('./connectionstate');
  20. const Types = require('./types');
  21. const Query = require('./query');
  22. const Model = require('./model');
  23. const Document = require('./document');
  24. const applyPlugins = require('./helpers/schema/applyPlugins');
  25. const get = require('./helpers/get');
  26. const legacyPluralize = require('mongoose-legacy-pluralize');
  27. const utils = require('./utils');
  28. const pkg = require('../package.json');
  29. const removeSubdocs = require('./plugins/removeSubdocs');
  30. const saveSubdocs = require('./plugins/saveSubdocs');
  31. const validateBeforeSave = require('./plugins/validateBeforeSave');
  32. const Aggregate = require('./aggregate');
  33. const PromiseProvider = require('./promise_provider');
  34. const shardingPlugin = require('./plugins/sharding');
  35. const defaultMongooseSymbol = Symbol.for('mongoose:default');
  36. require('./helpers/printJestWarning');
  37. /**
  38. * Mongoose constructor.
  39. *
  40. * The exports object of the `mongoose` module is an instance of this class.
  41. * Most apps will only use this one instance.
  42. *
  43. * @api public
  44. */
  45. function Mongoose(options) {
  46. this.connections = [];
  47. this.models = {};
  48. this.modelSchemas = {};
  49. // default global options
  50. this.options = {
  51. pluralization: true
  52. };
  53. const conn = this.createConnection(); // default connection
  54. conn.models = this.models;
  55. this._pluralize = legacyPluralize;
  56. // If a user creates their own Mongoose instance, give them a separate copy
  57. // of the `Schema` constructor so they get separate custom types. (gh-6933)
  58. if (!options || !options[defaultMongooseSymbol]) {
  59. const _this = this;
  60. this.Schema = function() {
  61. this.base = _this;
  62. return Schema.apply(this, arguments);
  63. };
  64. this.Schema.prototype = Object.create(Schema.prototype);
  65. Object.assign(this.Schema, Schema);
  66. this.Schema.base = this;
  67. this.Schema.Types = Object.assign({}, Schema.Types);
  68. } else {
  69. // Hack to work around babel's strange behavior with
  70. // `import mongoose, { Schema } from 'mongoose'`. Because `Schema` is not
  71. // an own property of a Mongoose global, Schema will be undefined. See gh-5648
  72. for (const key of ['Schema', 'model']) {
  73. this[key] = Mongoose.prototype[key];
  74. }
  75. }
  76. this.Schema.prototype.base = this;
  77. Object.defineProperty(this, 'plugins', {
  78. configurable: false,
  79. enumerable: true,
  80. writable: false,
  81. value: [
  82. [saveSubdocs, { deduplicate: true }],
  83. [validateBeforeSave, { deduplicate: true }],
  84. [shardingPlugin, { deduplicate: true }],
  85. [removeSubdocs, { deduplicate: true }]
  86. ]
  87. });
  88. }
  89. /**
  90. * Expose connection states for user-land
  91. *
  92. * @memberOf Mongoose
  93. * @property STATES
  94. * @api public
  95. */
  96. Mongoose.prototype.STATES = STATES;
  97. /**
  98. * The underlying driver this Mongoose instance uses to communicate with
  99. * the database. A driver is a Mongoose-specific interface that defines functions
  100. * like `find()`.
  101. *
  102. * @memberOf Mongoose
  103. * @property driver
  104. * @api public
  105. */
  106. Mongoose.prototype.driver = require('./driver');
  107. /**
  108. * Sets mongoose options
  109. *
  110. * ####Example:
  111. *
  112. * mongoose.set('test', value) // sets the 'test' option to `value`
  113. *
  114. * mongoose.set('debug', true) // enable logging collection methods + arguments to the console
  115. *
  116. * mongoose.set('debug', function(collectionName, methodName, arg1, arg2...) {}); // use custom function to log collection methods + arguments
  117. *
  118. * Currently supported options are:
  119. * - 'debug': prints the operations mongoose sends to MongoDB to the console
  120. * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
  121. * - 'useCreateIndex': false by default. Set to `true` to make Mongoose's default index build use `createIndex()` instead of `ensureIndex()` to avoid deprecation warnings from the MongoDB driver.
  122. * - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
  123. * - 'useNewUrlParser': false by default. Set to `true` to make all connections set the `useNewUrlParser` option by default
  124. * - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
  125. * - 'applyPluginsToDiscriminators': false by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
  126. * - 'objectIdGetter': true by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
  127. * - 'runValidators': false by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
  128. * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
  129. * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
  130. * - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
  131. * - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
  132. *
  133. * @param {String} key
  134. * @param {String|Function|Boolean} value
  135. * @api public
  136. */
  137. Mongoose.prototype.set = function(key, value) {
  138. if (arguments.length === 1) {
  139. return this.options[key];
  140. }
  141. this.options[key] = value;
  142. if (key === 'objectIdGetter') {
  143. if (value) {
  144. Object.defineProperty(mongoose.Types.ObjectId.prototype, '_id', {
  145. enumerable: false,
  146. configurable: true,
  147. get: function() {
  148. return this;
  149. }
  150. });
  151. } else {
  152. delete mongoose.Types.ObjectId.prototype._id;
  153. }
  154. }
  155. return this;
  156. };
  157. /**
  158. * Gets mongoose options
  159. *
  160. * ####Example:
  161. *
  162. * mongoose.get('test') // returns the 'test' value
  163. *
  164. * @param {String} key
  165. * @method get
  166. * @api public
  167. */
  168. Mongoose.prototype.get = Mongoose.prototype.set;
  169. /**
  170. * Creates a Connection instance.
  171. *
  172. * Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections.
  173. *
  174. *
  175. * _Options passed take precedence over options included in connection strings._
  176. *
  177. * ####Example:
  178. *
  179. * // with mongodb:// URI
  180. * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database');
  181. *
  182. * // and options
  183. * var opts = { db: { native_parser: true }}
  184. * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts);
  185. *
  186. * // replica sets
  187. * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database');
  188. *
  189. * // and options
  190. * var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
  191. * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
  192. *
  193. * // and options
  194. * var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
  195. * db = mongoose.createConnection('localhost', 'database', port, opts)
  196. *
  197. * // initialize now, connect later
  198. * db = mongoose.createConnection();
  199. * db.openUri('localhost', 'database', port, [opts]);
  200. *
  201. * @param {String} [uri] a mongodb:// URI
  202. * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html), except for 4 mongoose-specific options explained below.
  203. * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
  204. * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
  205. * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
  206. * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
  207. * @return {Connection} the created Connection object. Connections are thenable, so you can do `await mongoose.createConnection()`
  208. * @api public
  209. */
  210. Mongoose.prototype.createConnection = function(uri, options, callback) {
  211. const conn = new Connection(this);
  212. if (typeof options === 'function') {
  213. callback = options;
  214. options = null;
  215. }
  216. this.connections.push(conn);
  217. if (arguments.length > 0) {
  218. return conn.openUri(uri, options, callback);
  219. }
  220. return conn;
  221. };
  222. /**
  223. * Opens the default mongoose connection.
  224. *
  225. * ####Example:
  226. *
  227. * mongoose.connect('mongodb://user:pass@localhost:port/database');
  228. *
  229. * // replica sets
  230. * var uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase';
  231. * mongoose.connect(uri);
  232. *
  233. * // with options
  234. * mongoose.connect(uri, options);
  235. *
  236. * // optional callback that gets fired when initial connection completed
  237. * var uri = 'mongodb://nonexistent.domain:27000';
  238. * mongoose.connect(uri, function(error) {
  239. * // if error is truthy, the initial connection failed.
  240. * })
  241. *
  242. * @param {String} uri(s)
  243. * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html), except for 4 mongoose-specific options explained below.
  244. * @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
  245. * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
  246. * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
  247. * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
  248. * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
  249. * @param {Boolean} [options.useCreateIndex=true] Mongoose-specific option. If `true`, this connection will use [`createIndex()` instead of `ensureIndex()`](/docs/deprecations.html#-ensureindex-) for automatic index builds via [`Model.init()`](/docs/api.html#model_Model.init).
  250. * @param {Boolean} [options.useFindAndModify=true] True by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
  251. * @param {Boolean} [options.useNewUrlParser=false] False by default. Set to `true` to make all connections set the `useNewUrlParser` option by default.
  252. * @param {Function} [callback]
  253. * @see Mongoose#createConnection #index_Mongoose-createConnection
  254. * @api public
  255. * @return {Promise} resolves to `this` if connection succeeded
  256. */
  257. Mongoose.prototype.connect = function() {
  258. const _mongoose = this instanceof Mongoose ? this : mongoose;
  259. const conn = _mongoose.connection;
  260. return conn.openUri(arguments[0], arguments[1], arguments[2]).then(() => _mongoose);
  261. };
  262. /**
  263. * Runs `.close()` on all connections in parallel.
  264. *
  265. * @param {Function} [callback] called after all connection close, or when first error occurred.
  266. * @return {Promise} resolves when all connections are closed, or rejects with the first error that occurred.
  267. * @api public
  268. */
  269. Mongoose.prototype.disconnect = function(callback) {
  270. return utils.promiseOrCallback(callback, cb => {
  271. let remaining = this.connections.length;
  272. if (remaining <= 0) {
  273. return cb(null);
  274. }
  275. this.connections.forEach(conn => {
  276. conn.close(function(error) {
  277. if (error) {
  278. return cb(error);
  279. }
  280. if (!--remaining) {
  281. cb(null);
  282. }
  283. });
  284. });
  285. });
  286. };
  287. /**
  288. * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://docs.mongodb.com/manual/release-notes/3.6/#client-sessions)
  289. * for benefits like causal consistency, [retryable writes](https://docs.mongodb.com/manual/core/retryable-writes/),
  290. * and [transactions](http://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).
  291. *
  292. * Calling `mongoose.startSession()` is equivalent to calling `mongoose.connection.startSession()`.
  293. * Sessions are scoped to a connection, so calling `mongoose.startSession()`
  294. * starts a session on the [default mongoose connection](/docs/api.html#mongoose_Mongoose-connection).
  295. *
  296. * @param {Object} [options] see the [mongodb driver options](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#startSession)
  297. * @param {Boolean} [options.causalConsistency=true] set to false to disable causal consistency
  298. * @param {Function} [callback]
  299. * @return {Promise<ClientSession>} promise that resolves to a MongoDB driver `ClientSession`
  300. * @api public
  301. */
  302. Mongoose.prototype.startSession = function() {
  303. return this.connection.startSession.apply(this.connection, arguments);
  304. };
  305. /**
  306. * Getter/setter around function for pluralizing collection names.
  307. *
  308. * @param {Function|null} [fn] overwrites the function used to pluralize collection names
  309. * @return {Function|null} the current function used to pluralize collection names, defaults to the legacy function from `mongoose-legacy-pluralize`.
  310. * @api public
  311. */
  312. Mongoose.prototype.pluralize = function(fn) {
  313. if (arguments.length > 0) {
  314. this._pluralize = fn;
  315. }
  316. return this._pluralize;
  317. };
  318. /**
  319. * Defines a model or retrieves it.
  320. *
  321. * Models defined on the `mongoose` instance are available to all connection
  322. * created by the same `mongoose` instance.
  323. *
  324. * If you call `mongoose.model()` with twice the same name but a different schema,
  325. * you will get an `OverwriteModelError`. If you call `mongoose.model()` with
  326. * the same name and same schema, you'll get the same schema back.
  327. *
  328. * ####Example:
  329. *
  330. * var mongoose = require('mongoose');
  331. *
  332. * // define an Actor model with this mongoose instance
  333. * const Schema = new Schema({ name: String });
  334. * mongoose.model('Actor', schema);
  335. *
  336. * // create a new connection
  337. * var conn = mongoose.createConnection(..);
  338. *
  339. * // create Actor model
  340. * var Actor = conn.model('Actor', schema);
  341. * conn.model('Actor') === Actor; // true
  342. * conn.model('Actor', schema) === Actor; // true, same schema
  343. * conn.model('Actor', schema, 'actors') === Actor; // true, same schema and collection name
  344. *
  345. * // This throws an `OverwriteModelError` because the schema is different.
  346. * conn.model('Actor', new Schema({ name: String }));
  347. *
  348. * _When no `collection` argument is passed, Mongoose uses the model name. If you don't like this behavior, either pass a collection name, use `mongoose.pluralize()`, or set your schemas collection name option._
  349. *
  350. * ####Example:
  351. *
  352. * var schema = new Schema({ name: String }, { collection: 'actor' });
  353. *
  354. * // or
  355. *
  356. * schema.set('collection', 'actor');
  357. *
  358. * // or
  359. *
  360. * var collectionName = 'actor'
  361. * var M = mongoose.model('Actor', schema, collectionName)
  362. *
  363. * @param {String|Function} name model name or class extending Model
  364. * @param {Schema} [schema] the schema to use.
  365. * @param {String} [collection] name (optional, inferred from model name)
  366. * @param {Boolean} [skipInit] whether to skip initialization (defaults to false)
  367. * @return {Model} The model associated with `name`. Mongoose will create the model if it doesn't already exist.
  368. * @api public
  369. */
  370. Mongoose.prototype.model = function(name, schema, collection, skipInit) {
  371. const _mongoose = this instanceof Mongoose ? this : mongoose;
  372. let model;
  373. if (typeof name === 'function') {
  374. model = name;
  375. name = model.name;
  376. if (!(model.prototype instanceof Model)) {
  377. throw new _mongoose.Error('The provided class ' + name + ' must extend Model');
  378. }
  379. }
  380. if (typeof schema === 'string') {
  381. collection = schema;
  382. schema = false;
  383. }
  384. if (utils.isObject(schema) && !(schema.instanceOfSchema)) {
  385. schema = new Schema(schema);
  386. }
  387. if (schema && !schema.instanceOfSchema) {
  388. throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
  389. 'schema or a POJO');
  390. }
  391. if (typeof collection === 'boolean') {
  392. skipInit = collection;
  393. collection = null;
  394. }
  395. // handle internal options from connection.model()
  396. let options;
  397. if (skipInit && utils.isObject(skipInit)) {
  398. options = skipInit;
  399. skipInit = true;
  400. } else {
  401. options = {};
  402. }
  403. // look up schema for the collection.
  404. if (!_mongoose.modelSchemas[name]) {
  405. if (schema) {
  406. // cache it so we only apply plugins once
  407. _mongoose.modelSchemas[name] = schema;
  408. } else {
  409. throw new mongoose.Error.MissingSchemaError(name);
  410. }
  411. }
  412. const originalSchema = schema;
  413. if (schema) {
  414. if (_mongoose.get('cloneSchemas')) {
  415. schema = schema.clone();
  416. }
  417. _mongoose._applyPlugins(schema);
  418. }
  419. let sub;
  420. // connection.model() may be passing a different schema for
  421. // an existing model name. in this case don't read from cache.
  422. if (_mongoose.models[name] && options.cache !== false) {
  423. if (originalSchema &&
  424. originalSchema.instanceOfSchema &&
  425. originalSchema !== _mongoose.models[name].schema) {
  426. throw new _mongoose.Error.OverwriteModelError(name);
  427. }
  428. if (collection && collection !== _mongoose.models[name].collection.name) {
  429. // subclass current model with alternate collection
  430. model = _mongoose.models[name];
  431. schema = model.prototype.schema;
  432. sub = model.__subclass(_mongoose.connection, schema, collection);
  433. // do not cache the sub model
  434. return sub;
  435. }
  436. return _mongoose.models[name];
  437. }
  438. // ensure a schema exists
  439. if (!schema) {
  440. schema = this.modelSchemas[name];
  441. if (!schema) {
  442. throw new mongoose.Error.MissingSchemaError(name);
  443. }
  444. }
  445. // Apply relevant "global" options to the schema
  446. if (!('pluralization' in schema.options)) {
  447. schema.options.pluralization = _mongoose.options.pluralization;
  448. }
  449. if (!collection) {
  450. collection = schema.get('collection') ||
  451. utils.toCollectionName(name, _mongoose.pluralize());
  452. }
  453. const connection = options.connection || _mongoose.connection;
  454. model = _mongoose.Model.compile(model || name, schema, collection, connection, _mongoose);
  455. if (!skipInit) {
  456. // Errors handled internally, so safe to ignore error
  457. model.init(function $modelInitNoop() {});
  458. }
  459. if (options.cache === false) {
  460. return model;
  461. }
  462. _mongoose.models[name] = model;
  463. return _mongoose.models[name];
  464. };
  465. /**
  466. * Removes the model named `name` from the default connection, if it exists.
  467. * You can use this function to clean up any models you created in your tests to
  468. * prevent OverwriteModelErrors.
  469. *
  470. * Equivalent to `mongoose.connection.deleteModel(name)`.
  471. *
  472. * ####Example:
  473. *
  474. * mongoose.model('User', new Schema({ name: String }));
  475. * console.log(mongoose.model('User')); // Model object
  476. * mongoose.deleteModel('User');
  477. * console.log(mongoose.model('User')); // undefined
  478. *
  479. * // Usually useful in a Mocha `afterEach()` hook
  480. * afterEach(function() {
  481. * mongoose.deleteModel(/.+/); // Delete every model
  482. * });
  483. *
  484. * @api public
  485. * @param {String|RegExp} name if string, the name of the model to remove. If regexp, removes all models whose name matches the regexp.
  486. * @return {Mongoose} this
  487. */
  488. Mongoose.prototype.deleteModel = function(name) {
  489. this.connection.deleteModel(name);
  490. return this;
  491. };
  492. /**
  493. * Returns an array of model names created on this instance of Mongoose.
  494. *
  495. * ####Note:
  496. *
  497. * _Does not include names of models created using `connection.model()`._
  498. *
  499. * @api public
  500. * @return {Array}
  501. */
  502. Mongoose.prototype.modelNames = function() {
  503. const names = Object.keys(this.models);
  504. return names;
  505. };
  506. /**
  507. * Applies global plugins to `schema`.
  508. *
  509. * @param {Schema} schema
  510. * @api private
  511. */
  512. Mongoose.prototype._applyPlugins = function(schema, options) {
  513. options = options || {};
  514. options.applyPluginsToDiscriminators = get(this,
  515. 'options.applyPluginsToDiscriminators', false);
  516. applyPlugins(schema, this.plugins, options, '$globalPluginsApplied');
  517. };
  518. /**
  519. * Declares a global plugin executed on all Schemas.
  520. *
  521. * Equivalent to calling `.plugin(fn)` on each Schema you create.
  522. *
  523. * @param {Function} fn plugin callback
  524. * @param {Object} [opts] optional options
  525. * @return {Mongoose} this
  526. * @see plugins ./plugins.html
  527. * @api public
  528. */
  529. Mongoose.prototype.plugin = function(fn, opts) {
  530. this.plugins.push([fn, opts]);
  531. return this;
  532. };
  533. /**
  534. * The Mongoose module's default connection. Equivalent to `mongoose.connections][0]`, see [`connections`](#mongoose_Mongoose-connections).
  535. *
  536. * ####Example:
  537. *
  538. * var mongoose = require('mongoose');
  539. * mongoose.connect(...);
  540. * mongoose.connection.on('error', cb);
  541. *
  542. * This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
  543. *
  544. * To create a new connection, use [`createConnection()`](#mongoose_Mongoose-createConnection).
  545. *
  546. * @memberOf Mongoose
  547. * @instance
  548. * @property {Connection} connection
  549. * @api public
  550. */
  551. Mongoose.prototype.__defineGetter__('connection', function() {
  552. return this.connections[0];
  553. });
  554. Mongoose.prototype.__defineSetter__('connection', function(v) {
  555. if (v instanceof Connection) {
  556. this.connections[0] = v;
  557. this.models = v.models;
  558. }
  559. });
  560. /**
  561. * An array containing all [connections](connections.html) associated with this
  562. * Mongoose instance. By default, there is 1 connection. Calling
  563. * [`createConnection()`](#mongoose_Mongoose-createConnection) adds a connection
  564. * to this array.
  565. *
  566. * ####Example:
  567. *
  568. * const mongoose = require('mongoose');
  569. * mongoose.connections.length; // 1, just the default connection
  570. * mongoose.connections[0] === mongoose.connection; // true
  571. *
  572. * mongoose.createConnection('mongodb://localhost:27017/test');
  573. * mongoose.connections.length; // 2
  574. *
  575. * @memberOf Mongoose
  576. * @instance
  577. * @property {Array} connections
  578. * @api public
  579. */
  580. Mongoose.prototype.connections;
  581. /*!
  582. * Driver dependent APIs
  583. */
  584. const driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
  585. /*!
  586. * Connection
  587. */
  588. const Connection = require(driver + '/connection');
  589. /*!
  590. * Collection
  591. */
  592. const Collection = require(driver + '/collection');
  593. /**
  594. * The Mongoose Aggregate constructor
  595. *
  596. * @method Aggregate
  597. * @api public
  598. */
  599. Mongoose.prototype.Aggregate = Aggregate;
  600. /**
  601. * The Mongoose Collection constructor
  602. *
  603. * @method Collection
  604. * @api public
  605. */
  606. Mongoose.prototype.Collection = Collection;
  607. /**
  608. * The Mongoose [Connection](#connection_Connection) constructor
  609. *
  610. * @memberOf Mongoose
  611. * @instance
  612. * @method Connection
  613. * @api public
  614. */
  615. Mongoose.prototype.Connection = Connection;
  616. /**
  617. * The Mongoose version
  618. *
  619. * #### Example
  620. *
  621. * console.log(mongoose.version); // '5.x.x'
  622. *
  623. * @property version
  624. * @api public
  625. */
  626. Mongoose.prototype.version = pkg.version;
  627. /**
  628. * The Mongoose constructor
  629. *
  630. * The exports of the mongoose module is an instance of this class.
  631. *
  632. * ####Example:
  633. *
  634. * var mongoose = require('mongoose');
  635. * var mongoose2 = new mongoose.Mongoose();
  636. *
  637. * @method Mongoose
  638. * @api public
  639. */
  640. Mongoose.prototype.Mongoose = Mongoose;
  641. /**
  642. * The Mongoose [Schema](#schema_Schema) constructor
  643. *
  644. * ####Example:
  645. *
  646. * var mongoose = require('mongoose');
  647. * var Schema = mongoose.Schema;
  648. * var CatSchema = new Schema(..);
  649. *
  650. * @method Schema
  651. * @api public
  652. */
  653. Mongoose.prototype.Schema = Schema;
  654. /**
  655. * The Mongoose [SchemaType](#schematype_SchemaType) constructor
  656. *
  657. * @method SchemaType
  658. * @api public
  659. */
  660. Mongoose.prototype.SchemaType = SchemaType;
  661. /**
  662. * The various Mongoose SchemaTypes.
  663. *
  664. * ####Note:
  665. *
  666. * _Alias of mongoose.Schema.Types for backwards compatibility._
  667. *
  668. * @property SchemaTypes
  669. * @see Schema.SchemaTypes #schema_Schema.Types
  670. * @api public
  671. */
  672. Mongoose.prototype.SchemaTypes = Schema.Types;
  673. /**
  674. * The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
  675. *
  676. * @method VirtualType
  677. * @api public
  678. */
  679. Mongoose.prototype.VirtualType = VirtualType;
  680. /**
  681. * The various Mongoose Types.
  682. *
  683. * ####Example:
  684. *
  685. * var mongoose = require('mongoose');
  686. * var array = mongoose.Types.Array;
  687. *
  688. * ####Types:
  689. *
  690. * - [ObjectId](#types-objectid-js)
  691. * - [Buffer](#types-buffer-js)
  692. * - [SubDocument](#types-embedded-js)
  693. * - [Array](#types-array-js)
  694. * - [DocumentArray](#types-documentarray-js)
  695. *
  696. * Using this exposed access to the `ObjectId` type, we can construct ids on demand.
  697. *
  698. * var ObjectId = mongoose.Types.ObjectId;
  699. * var id1 = new ObjectId;
  700. *
  701. * @property Types
  702. * @api public
  703. */
  704. Mongoose.prototype.Types = Types;
  705. /**
  706. * The Mongoose [Query](#query_Query) constructor.
  707. *
  708. * @method Query
  709. * @api public
  710. */
  711. Mongoose.prototype.Query = Query;
  712. /**
  713. * The Mongoose [Promise](#promise_Promise) constructor.
  714. *
  715. * @memberOf Mongoose
  716. * @instance
  717. * @property Promise
  718. * @api public
  719. */
  720. Object.defineProperty(Mongoose.prototype, 'Promise', {
  721. get: function() {
  722. return PromiseProvider.get();
  723. },
  724. set: function(lib) {
  725. PromiseProvider.set(lib);
  726. }
  727. });
  728. /**
  729. * Storage layer for mongoose promises
  730. *
  731. * @method PromiseProvider
  732. * @api public
  733. */
  734. Mongoose.prototype.PromiseProvider = PromiseProvider;
  735. /**
  736. * The Mongoose [Model](#model_Model) constructor.
  737. *
  738. * @method Model
  739. * @api public
  740. */
  741. Mongoose.prototype.Model = Model;
  742. /**
  743. * The Mongoose [Document](#document-js) constructor.
  744. *
  745. * @method Document
  746. * @api public
  747. */
  748. Mongoose.prototype.Document = Document;
  749. /**
  750. * The Mongoose DocumentProvider constructor. Mongoose users should not have to
  751. * use this directly
  752. *
  753. * @method DocumentProvider
  754. * @api public
  755. */
  756. Mongoose.prototype.DocumentProvider = require('./document_provider');
  757. /**
  758. * The Mongoose ObjectId [SchemaType](/docs/schematypes.html). Used for
  759. * declaring paths in your schema that should be
  760. * [MongoDB ObjectIds](https://docs.mongodb.com/manual/reference/method/ObjectId/).
  761. * Do not use this to create a new ObjectId instance, use `mongoose.Types.ObjectId`
  762. * instead.
  763. *
  764. * ####Example:
  765. *
  766. * const childSchema = new Schema({ parentId: mongoose.ObjectId });
  767. *
  768. * @property ObjectId
  769. * @api public
  770. */
  771. Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
  772. /**
  773. * The Mongoose Decimal128 [SchemaType](/docs/schematypes.html). Used for
  774. * declaring paths in your schema that should be
  775. * [128-bit decimal floating points](http://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-decimal.html).
  776. * Do not use this to create a new Decimal128 instance, use `mongoose.Types.Decimal128`
  777. * instead.
  778. *
  779. * ####Example:
  780. *
  781. * const vehicleSchema = new Schema({ fuelLevel: mongoose.Decimal128 });
  782. *
  783. * @property Decimal128
  784. * @api public
  785. */
  786. Mongoose.prototype.Decimal128 = SchemaTypes.Decimal128;
  787. /**
  788. * The Mongoose Mixed [SchemaType](/docs/schematypes.html). Used for
  789. * declaring paths in your schema that Mongoose's change tracking, casting,
  790. * and validation should ignore.
  791. *
  792. * ####Example:
  793. *
  794. * const schema = new Schema({ arbitrary: mongoose.Mixed });
  795. *
  796. * @property Mixed
  797. * @api public
  798. */
  799. Mongoose.prototype.Mixed = SchemaTypes.Mixed;
  800. /**
  801. * The Mongoose Number [SchemaType](/docs/schematypes.html). Used for
  802. * declaring paths in your schema that Mongoose should cast to numbers.
  803. *
  804. * ####Example:
  805. *
  806. * const schema = new Schema({ num: mongoose.Number });
  807. * // Equivalent to:
  808. * const schema = new Schema({ num: 'number' });
  809. *
  810. * @property Number
  811. * @api public
  812. */
  813. Mongoose.prototype.Number = SchemaTypes.Number;
  814. /**
  815. * The [MongooseError](#error_MongooseError) constructor.
  816. *
  817. * @method Error
  818. * @api public
  819. */
  820. Mongoose.prototype.Error = require('./error');
  821. /**
  822. * Mongoose uses this function to get the current time when setting
  823. * [timestamps](/docs/guide.html#timestamps). You may stub out this function
  824. * using a tool like [Sinon](https://www.npmjs.com/package/sinon) for testing.
  825. *
  826. * @method now
  827. * @returns Date the current time
  828. * @api public
  829. */
  830. Mongoose.prototype.now = function now() { return new Date(); };
  831. /**
  832. * The Mongoose CastError constructor
  833. *
  834. * @method CastError
  835. * @param {String} type The name of the type
  836. * @param {Any} value The value that failed to cast
  837. * @param {String} path The path `a.b.c` in the doc where this cast error occurred
  838. * @param {Error} [reason] The original error that was thrown
  839. * @api public
  840. */
  841. Mongoose.prototype.CastError = require('./error/cast');
  842. /**
  843. * The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses.
  844. *
  845. * @property mongo
  846. * @api public
  847. */
  848. Mongoose.prototype.mongo = require('mongodb');
  849. /**
  850. * The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses.
  851. *
  852. * @property mquery
  853. * @api public
  854. */
  855. Mongoose.prototype.mquery = require('mquery');
  856. /*!
  857. * The exports object is an instance of Mongoose.
  858. *
  859. * @api public
  860. */
  861. const mongoose = module.exports = exports = new Mongoose({
  862. [defaultMongooseSymbol]: true
  863. });