index.js 30 KB

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