UNPKG

51.8 kBJavaScriptView Raw
1'use strict';
2
3/*!
4 * Module dependencies.
5 */
6
7const Document = require('./document');
8const EventEmitter = require('events').EventEmitter;
9const Kareem = require('kareem');
10const Schema = require('./schema');
11const SchemaType = require('./schemaType');
12const SchemaTypes = require('./schema/index');
13const VirtualType = require('./virtualType');
14const STATES = require('./connectionState');
15const VALID_OPTIONS = require('./validOptions');
16const Types = require('./types');
17const Query = require('./query');
18const Model = require('./model');
19const applyPlugins = require('./helpers/schema/applyPlugins');
20const builtinPlugins = require('./plugins');
21const driver = require('./driver');
22const legacyPluralize = require('./helpers/pluralize');
23const utils = require('./utils');
24const pkg = require('../package.json');
25const cast = require('./cast');
26
27const Aggregate = require('./aggregate');
28const trusted = require('./helpers/query/trusted').trusted;
29const sanitizeFilter = require('./helpers/query/sanitizeFilter');
30const isBsonType = require('./helpers/isBsonType');
31const MongooseError = require('./error/mongooseError');
32const SetOptionError = require('./error/setOptionError');
33const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbeddedDiscriminators');
34
35const defaultMongooseSymbol = Symbol.for('mongoose:default');
36const defaultConnectionSymbol = Symbol('mongoose:defaultConnection');
37
38require('./helpers/printJestWarning');
39
40const objectIdHexRegexp = /^[0-9A-Fa-f]{24}$/;
41
42const { AsyncLocalStorage } = require('node:async_hooks');
43
44/**
45 * Mongoose constructor.
46 *
47 * The exports object of the `mongoose` module is an instance of this class.
48 * Most apps will only use this one instance.
49 *
50 * #### Example:
51 *
52 * const mongoose = require('mongoose');
53 * mongoose instanceof mongoose.Mongoose; // true
54 *
55 * // Create a new Mongoose instance with its own `connect()`, `set()`, `model()`, etc.
56 * const m = new mongoose.Mongoose();
57 *
58 * @api public
59 * @param {Object} options see [`Mongoose#set()` docs](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.set())
60 */
61function Mongoose(options) {
62 this.connections = [];
63 this.nextConnectionId = 0;
64 this.models = {};
65 this.events = new EventEmitter();
66 this.__driver = driver.get();
67 // default global options
68 this.options = Object.assign({
69 pluralization: true,
70 autoIndex: true,
71 autoCreate: true,
72 autoSearchIndex: false
73 }, options);
74 const createInitialConnection = utils.getOption('createInitialConnection', this.options) ?? true;
75 if (createInitialConnection && this.__driver != null) {
76 _createDefaultConnection(this);
77 }
78
79 if (this.options.pluralization) {
80 this._pluralize = legacyPluralize;
81 }
82
83 // If a user creates their own Mongoose instance, give them a separate copy
84 // of the `Schema` constructor so they get separate custom types. (gh-6933)
85 if (!options || !options[defaultMongooseSymbol]) {
86 const _this = this;
87 this.Schema = function() {
88 this.base = _this;
89 return Schema.apply(this, arguments);
90 };
91 this.Schema.prototype = Object.create(Schema.prototype);
92
93 Object.assign(this.Schema, Schema);
94 this.Schema.base = this;
95 this.Schema.Types = Object.assign({}, Schema.Types);
96 } else {
97 // Hack to work around babel's strange behavior with
98 // `import mongoose, { Schema } from 'mongoose'`. Because `Schema` is not
99 // an own property of a Mongoose global, Schema will be undefined. See gh-5648
100 for (const key of ['Schema', 'model']) {
101 this[key] = Mongoose.prototype[key];
102 }
103 }
104 this.Schema.prototype.base = this;
105
106 if (options?.transactionAsyncLocalStorage) {
107 this.transactionAsyncLocalStorage = new AsyncLocalStorage();
108 }
109
110 Object.defineProperty(this, 'plugins', {
111 configurable: false,
112 enumerable: true,
113 writable: false,
114 value: Object.values(builtinPlugins).map(plugin => ([plugin, { deduplicate: true }]))
115 });
116}
117
118Mongoose.prototype.cast = cast;
119/**
120 * Expose connection states for user-land
121 *
122 * @memberOf Mongoose
123 * @property STATES
124 * @api public
125 */
126Mongoose.prototype.STATES = STATES;
127
128/**
129 * Expose connection states for user-land
130 *
131 * @memberOf Mongoose
132 * @property ConnectionStates
133 * @api public
134 */
135Mongoose.prototype.ConnectionStates = STATES;
136
137/**
138 * Object with `get()` and `set()` containing the underlying driver this Mongoose instance
139 * uses to communicate with the database. A driver is a Mongoose-specific interface that defines functions
140 * like `find()`.
141 *
142 * @deprecated
143 * @memberOf Mongoose
144 * @property driver
145 * @api public
146 */
147
148Mongoose.prototype.driver = driver;
149
150/**
151 * Overwrites the current driver used by this Mongoose instance. A driver is a
152 * Mongoose-specific interface that defines functions like `find()`.
153 *
154 * @memberOf Mongoose
155 * @method setDriver
156 * @api public
157 */
158
159Mongoose.prototype.setDriver = function setDriver(driver) {
160 const _mongoose = this instanceof Mongoose ? this : mongoose;
161
162 if (_mongoose.__driver === driver) {
163 return _mongoose;
164 }
165
166 const openConnection = _mongoose.connections && _mongoose.connections.find(conn => conn.readyState !== STATES.disconnected);
167 if (openConnection) {
168 const msg = 'Cannot modify Mongoose driver if a connection is already open. ' +
169 'Call `mongoose.disconnect()` before modifying the driver';
170 throw new MongooseError(msg);
171 }
172 _mongoose.__driver = driver;
173
174 if (Array.isArray(driver.plugins)) {
175 for (const plugin of driver.plugins) {
176 if (typeof plugin === 'function') {
177 _mongoose.plugin(plugin);
178 }
179 }
180 }
181
182 const Connection = driver.Connection;
183 const oldDefaultConnection = _mongoose.connections[0];
184 _mongoose.connections = [new Connection(_mongoose)];
185 _mongoose.connections[0].models = _mongoose.models;
186 if (oldDefaultConnection == null) {
187 return _mongoose;
188 }
189
190 // Update all models that pointed to the old default connection to
191 // the new default connection, including collections
192 for (const model of Object.values(_mongoose.models)) {
193 if (model.db !== oldDefaultConnection) {
194 continue;
195 }
196 model.$__updateConnection(_mongoose.connections[0]);
197 }
198
199 return _mongoose;
200};
201
202/**
203 * Sets mongoose options
204 *
205 * `key` can be used a object to set multiple options at once.
206 * If a error gets thrown for one option, other options will still be evaluated.
207 *
208 * #### Example:
209 *
210 * mongoose.set('test', value) // sets the 'test' option to `value`
211 *
212 * mongoose.set('debug', true) // enable logging collection methods + arguments to the console/file
213 *
214 * mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {}); // use custom function to log collection methods + arguments
215 *
216 * mongoose.set({ debug: true, autoIndex: false }); // set multiple options at once
217 *
218 * Currently supported options are:
219 * - `allowDiskUse`: Set to `true` to set `allowDiskUse` to true to all aggregation operations by default.
220 * - `applyPluginsToChildSchemas`: `true` by default. Set to false to skip applying global plugins to child schemas
221 * - `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.
222 * - `autoCreate`: Set to `true` to make Mongoose call [`Model.createCollection()`](https://mongoosejs.com/docs/api/model.html#Model.createCollection()) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
223 * - `autoIndex`: `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
224 * - `bufferCommands`: enable/disable mongoose's buffering mechanism for all connections and models
225 * - `bufferTimeoutMS`: If bufferCommands is on, this option sets the maximum amount of time Mongoose buffering will wait before throwing an error. If not specified, Mongoose will use 10000 (10 seconds).
226 * - `cloneSchemas`: `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
227 * - `debug`: If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
228 * - `id`: If `true`, adds a `id` virtual to all schemas unless overwritten on a per-schema basis.
229 * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.immutable) which means you can update the `createdAt`
230 * - `maxTimeMS`: If set, attaches [maxTimeMS](https://www.mongodb.com/docs/manual/reference/operator/meta/maxTimeMS/) to every query
231 * - `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.
232 * - `overwriteModels`: Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
233 * - `returnOriginal`: If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](https://mongoosejs.com/docs/tutorials/findoneandupdate.html) for more information.
234 * - `runValidators`: `false` by default. Set to true to enable [update validators](https://mongoosejs.com/docs/validation.html#update-validators) for all validators by default.
235 * - `sanitizeFilter`: `false` by default. Set to true to enable the [sanitization of the query filters](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.sanitizeFilter()) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
236 * - `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.
237 * - `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
238 * - `strictQuery`: `false` by default. May be `false`, `true`, or `'throw'`. Sets the default [strictQuery](https://mongoosejs.com/docs/guide.html#strictQuery) mode for schemas.
239 * - `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toJSON()), for determining how Mongoose documents get serialized by `JSON.stringify()`
240 * - `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject())
241 *
242 * @param {String|Object} key The name of the option or a object of multiple key-value pairs
243 * @param {String|Function|Boolean} value The value of the option, unused if "key" is a object
244 * @returns {Mongoose} The used Mongoose instnace
245 * @api public
246 */
247
248Mongoose.prototype.set = function(key, value) {
249 const _mongoose = this instanceof Mongoose ? this : mongoose;
250
251 if (arguments.length === 1 && typeof key !== 'object') {
252 if (VALID_OPTIONS.indexOf(key) === -1) {
253 const error = new SetOptionError();
254 error.addError(key, new SetOptionError.SetOptionInnerError(key));
255 throw error;
256 }
257
258 return _mongoose.options[key];
259 }
260
261 let options = {};
262
263 if (arguments.length === 2) {
264 options = { [key]: value };
265 }
266
267 if (arguments.length === 1 && typeof key === 'object') {
268 options = key;
269 }
270
271 // array for errors to collect all errors for all key-value pairs, like ".validate"
272 let error = undefined;
273
274 for (const [optionKey, optionValue] of Object.entries(options)) {
275 if (VALID_OPTIONS.indexOf(optionKey) === -1) {
276 if (!error) {
277 error = new SetOptionError();
278 }
279 error.addError(optionKey, new SetOptionError.SetOptionInnerError(optionKey));
280 continue;
281 }
282
283 _mongoose.options[optionKey] = optionValue;
284
285 if (optionKey === 'objectIdGetter') {
286 if (optionValue) {
287 Object.defineProperty(_mongoose.Types.ObjectId.prototype, '_id', {
288 enumerable: false,
289 configurable: true,
290 get: function() {
291 return this;
292 }
293 });
294 } else {
295 delete _mongoose.Types.ObjectId.prototype._id;
296 }
297 } else if (optionKey === 'transactionAsyncLocalStorage') {
298 if (optionValue && !_mongoose.transactionAsyncLocalStorage) {
299 _mongoose.transactionAsyncLocalStorage = new AsyncLocalStorage();
300 } else if (!optionValue && _mongoose.transactionAsyncLocalStorage) {
301 delete _mongoose.transactionAsyncLocalStorage;
302 }
303 } else if (optionKey === 'createInitialConnection') {
304 if (optionValue && !_mongoose.connection) {
305 _createDefaultConnection(_mongoose);
306 } else if (optionValue === false && _mongoose.connection && _mongoose.connection[defaultConnectionSymbol]) {
307 if (_mongoose.connection.readyState === STATES.disconnected && Object.keys(_mongoose.connection.models).length === 0) {
308 _mongoose.connections.shift();
309 }
310 }
311 }
312 }
313
314 if (error) {
315 throw error;
316 }
317
318 return _mongoose;
319};
320
321/**
322 * Gets mongoose options
323 *
324 * #### Example:
325 *
326 * mongoose.get('test') // returns the 'test' value
327 *
328 * @param {String} key
329 * @method get
330 * @api public
331 */
332
333Mongoose.prototype.get = Mongoose.prototype.set;
334
335/**
336 * Creates a Connection instance.
337 *
338 * Each `connection` instance maps to a single database. This method is helpful when managing multiple db connections.
339 *
340 *
341 * _Options passed take precedence over options included in connection strings._
342 *
343 * #### Example:
344 *
345 * // with mongodb:// URI
346 * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database');
347 *
348 * // and options
349 * const opts = { db: { native_parser: true }}
350 * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database', opts);
351 *
352 * // replica sets
353 * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database');
354 *
355 * // and options
356 * const opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
357 * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database', opts);
358 *
359 * // initialize now, connect later
360 * db = mongoose.createConnection();
361 * db.openUri('127.0.0.1', 'database', port, [opts]);
362 *
363 * @param {String} uri mongodb URI to connect to
364 * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html), except for 4 mongoose-specific options explained below.
365 * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](https://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
366 * @param {String} [options.dbName] The name of the database you want to use. If not provided, Mongoose uses the database name from connection string.
367 * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
368 * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
369 * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
370 * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html#promiseLibrary).
371 * @param {Number} [options.maxPoolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
372 * @param {Number} [options.minPoolSize=1] The minimum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
373 * @param {Number} [options.socketTimeoutMS=0] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. Defaults to 0, which means Node.js will not time out the socket due to inactivity. A socket may be inactive because of either no activity or a long-running operation. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
374 * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
375 * @return {Connection} the created Connection object. Connections are not thenable, so you can't do `await mongoose.createConnection()`. To await use `mongoose.createConnection(uri).asPromise()` instead.
376 * @api public
377 */
378
379Mongoose.prototype.createConnection = function(uri, options) {
380 const _mongoose = this instanceof Mongoose ? this : mongoose;
381
382 const Connection = _mongoose.__driver.Connection;
383 const conn = new Connection(_mongoose);
384 _mongoose.connections.push(conn);
385 _mongoose.nextConnectionId++;
386 _mongoose.events.emit('createConnection', conn);
387
388 if (arguments.length > 0) {
389 conn.openUri(uri, { ...options, _fireAndForget: true });
390 }
391
392 return conn;
393};
394
395/**
396 * Opens the default mongoose connection.
397 *
398 * #### Example:
399 *
400 * mongoose.connect('mongodb://user:pass@127.0.0.1:port/database');
401 *
402 * // replica sets
403 * const uri = 'mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/mydatabase';
404 * mongoose.connect(uri);
405 *
406 * // with options
407 * mongoose.connect(uri, options);
408 *
409 * // optional callback that gets fired when initial connection completed
410 * const uri = 'mongodb://nonexistent.domain:27000';
411 * mongoose.connect(uri, function(error) {
412 * // if error is truthy, the initial connection failed.
413 * })
414 *
415 * @param {String} uri mongodb URI to connect to
416 * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html), except for 4 mongoose-specific options explained below.
417 * @param {Boolean} [options.bufferCommands=true] Mongoose specific option. Set to false to [disable buffering](https://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection.
418 * @param {Number} [options.bufferTimeoutMS=10000] Mongoose specific option. If `bufferCommands` is true, Mongoose will throw an error after `bufferTimeoutMS` if the operation is still buffered.
419 * @param {String} [options.dbName] The name of the database we want to use. If not provided, use database name from connection string.
420 * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
421 * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
422 * @param {Number} [options.maxPoolSize=100] The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
423 * @param {Number} [options.minPoolSize=0] The minimum number of sockets the MongoDB driver will keep open for this connection.
424 * @param {Number} [options.serverSelectionTimeoutMS] If `useUnifiedTopology = true`, the MongoDB driver will try to find a server to send any given operation to, and keep retrying for `serverSelectionTimeoutMS` milliseconds before erroring out. If not set, the MongoDB driver defaults to using `30000` (30 seconds).
425 * @param {Number} [options.heartbeatFrequencyMS] If `useUnifiedTopology = true`, the MongoDB driver sends a heartbeat every `heartbeatFrequencyMS` to check on the status of the connection. A heartbeat is subject to `serverSelectionTimeoutMS`, so the MongoDB driver will retry failed heartbeats for up to 30 seconds by default. Mongoose only emits a `'disconnected'` event after a heartbeat has failed, so you may want to decrease this setting to reduce the time between when your server goes down and when Mongoose emits `'disconnected'`. We recommend you do **not** set this setting below 1000, too many heartbeats can lead to performance degradation.
426 * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
427 * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html#promiseLibrary).
428 * @param {Number} [options.socketTimeoutMS=0] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. `socketTimeoutMS` defaults to 0, which means Node.js will not time out the socket due to inactivity. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
429 * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
430 * @param {Boolean} [options.autoCreate=false] Set to `true` to make Mongoose automatically call `createCollection()` on every model created on this connection.
431 * @param {Function} [callback]
432 * @see Mongoose#createConnection https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.createConnection()
433 * @api public
434 * @return {Promise} resolves to `this` if connection succeeded
435 */
436
437Mongoose.prototype.connect = async function connect(uri, options) {
438 if (typeof options === 'function' || (arguments.length >= 3 && typeof arguments[2] === 'function')) {
439 throw new MongooseError('Mongoose.prototype.connect() no longer accepts a callback');
440 }
441
442 const _mongoose = this instanceof Mongoose ? this : mongoose;
443 if (_mongoose.connection == null) {
444 _createDefaultConnection(_mongoose);
445 }
446 const conn = _mongoose.connection;
447
448 return conn.openUri(uri, options).then(() => _mongoose);
449};
450
451/**
452 * Runs `.close()` on all connections in parallel.
453 *
454 * @return {Promise} resolves when all connections are closed, or rejects with the first error that occurred.
455 * @api public
456 */
457
458Mongoose.prototype.disconnect = async function disconnect() {
459 if (arguments.length >= 1 && typeof arguments[0] === 'function') {
460 throw new MongooseError('Mongoose.prototype.disconnect() no longer accepts a callback');
461 }
462
463 const _mongoose = this instanceof Mongoose ? this : mongoose;
464
465 const remaining = _mongoose.connections.length;
466 if (remaining <= 0) {
467 return;
468 }
469 await Promise.all(_mongoose.connections.map(conn => conn.close()));
470};
471
472/**
473 * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://www.mongodb.com/docs/manual/release-notes/3.6/#client-sessions)
474 * for benefits like causal consistency, [retryable writes](https://www.mongodb.com/docs/manual/core/retryable-writes/),
475 * and [transactions](https://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html).
476 *
477 * Calling `mongoose.startSession()` is equivalent to calling `mongoose.connection.startSession()`.
478 * Sessions are scoped to a connection, so calling `mongoose.startSession()`
479 * starts a session on the [default mongoose connection](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.connection).
480 *
481 * @param {Object} [options] see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/MongoClient.html#startSession)
482 * @param {Boolean} [options.causalConsistency=true] set to false to disable causal consistency
483 * @param {Function} [callback]
484 * @return {Promise<ClientSession>} promise that resolves to a MongoDB driver `ClientSession`
485 * @api public
486 */
487
488Mongoose.prototype.startSession = function() {
489 const _mongoose = this instanceof Mongoose ? this : mongoose;
490
491 return _mongoose.connection.startSession.apply(_mongoose.connection, arguments);
492};
493
494/**
495 * Getter/setter around function for pluralizing collection names.
496 *
497 * @param {Function|null} [fn] overwrites the function used to pluralize collection names
498 * @return {Function|null} the current function used to pluralize collection names, defaults to the legacy function from `mongoose-legacy-pluralize`.
499 * @api public
500 */
501
502Mongoose.prototype.pluralize = function(fn) {
503 const _mongoose = this instanceof Mongoose ? this : mongoose;
504
505 if (arguments.length > 0) {
506 _mongoose._pluralize = fn;
507 }
508 return _mongoose._pluralize;
509};
510
511/**
512 * Defines a model or retrieves it.
513 *
514 * Models defined on the `mongoose` instance are available to all connection
515 * created by the same `mongoose` instance.
516 *
517 * If you call `mongoose.model()` with twice the same name but a different schema,
518 * you will get an `OverwriteModelError`. If you call `mongoose.model()` with
519 * the same name and same schema, you'll get the same schema back.
520 *
521 * #### Example:
522 *
523 * const mongoose = require('mongoose');
524 *
525 * // define an Actor model with this mongoose instance
526 * const schema = new Schema({ name: String });
527 * mongoose.model('Actor', schema);
528 *
529 * // create a new connection
530 * const conn = mongoose.createConnection(..);
531 *
532 * // create Actor model
533 * const Actor = conn.model('Actor', schema);
534 * conn.model('Actor') === Actor; // true
535 * conn.model('Actor', schema) === Actor; // true, same schema
536 * conn.model('Actor', schema, 'actors') === Actor; // true, same schema and collection name
537 *
538 * // This throws an `OverwriteModelError` because the schema is different.
539 * conn.model('Actor', new Schema({ name: String }));
540 *
541 * _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._
542 *
543 * #### Example:
544 *
545 * const schema = new Schema({ name: String }, { collection: 'actor' });
546 *
547 * // or
548 *
549 * schema.set('collection', 'actor');
550 *
551 * // or
552 *
553 * const collectionName = 'actor';
554 * const M = mongoose.model('Actor', schema, collectionName);
555 *
556 * @param {String|Function} name model name or class extending Model
557 * @param {Schema} [schema] the schema to use.
558 * @param {String} [collection] name (optional, inferred from model name)
559 * @param {Object} [options]
560 * @param {Boolean} [options.overwriteModels=false] If true, overwrite existing models with the same name to avoid `OverwriteModelError`
561 * @return {Model} The model associated with `name`. Mongoose will create the model if it doesn't already exist.
562 * @api public
563 */
564
565Mongoose.prototype.model = function(name, schema, collection, options) {
566 const _mongoose = this instanceof Mongoose ? this : mongoose;
567
568 if (typeof schema === 'string') {
569 collection = schema;
570 schema = false;
571 }
572
573 if (arguments.length === 1) {
574 const model = _mongoose.models[name];
575 if (!model) {
576 throw new MongooseError.MissingSchemaError(name);
577 }
578 return model;
579 }
580
581 if (utils.isObject(schema) && !(schema instanceof Schema)) {
582 schema = new Schema(schema);
583 }
584 if (schema && !(schema instanceof Schema)) {
585 throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
586 'schema or a POJO');
587 }
588
589 // handle internal options from connection.model()
590 options = options || {};
591
592 const originalSchema = schema;
593 if (schema) {
594 if (_mongoose.get('cloneSchemas')) {
595 schema = schema.clone();
596 }
597 _mongoose._applyPlugins(schema);
598 }
599
600 // connection.model() may be passing a different schema for
601 // an existing model name. in this case don't read from cache.
602 const overwriteModels = _mongoose.options.hasOwnProperty('overwriteModels') ?
603 _mongoose.options.overwriteModels :
604 options.overwriteModels;
605 if (_mongoose.models.hasOwnProperty(name) && options.cache !== false && overwriteModels !== true) {
606 if (originalSchema &&
607 originalSchema.instanceOfSchema &&
608 originalSchema !== _mongoose.models[name].schema) {
609 throw new _mongoose.Error.OverwriteModelError(name);
610 }
611 if (collection && collection !== _mongoose.models[name].collection.name) {
612 // subclass current model with alternate collection
613 const model = _mongoose.models[name];
614 schema = model.prototype.schema;
615 const sub = model.__subclass(_mongoose.connection, schema, collection);
616 // do not cache the sub model
617 return sub;
618 }
619 return _mongoose.models[name];
620 }
621 if (schema == null) {
622 throw new _mongoose.Error.MissingSchemaError(name);
623 }
624
625 const model = _mongoose._model(name, schema, collection, options);
626 _mongoose.connection.models[name] = model;
627 _mongoose.models[name] = model;
628
629 return model;
630};
631
632/*!
633 * ignore
634 */
635
636Mongoose.prototype._model = function(name, schema, collection, options) {
637 const _mongoose = this instanceof Mongoose ? this : mongoose;
638
639 let model;
640 if (typeof name === 'function') {
641 model = name;
642 name = model.name;
643 if (!(model.prototype instanceof Model)) {
644 throw new _mongoose.Error('The provided class ' + name + ' must extend Model');
645 }
646 }
647
648 if (schema) {
649 if (_mongoose.get('cloneSchemas')) {
650 schema = schema.clone();
651 }
652 _mongoose._applyPlugins(schema);
653 }
654
655 // Apply relevant "global" options to the schema
656 if (schema == null || !('pluralization' in schema.options)) {
657 schema.options.pluralization = _mongoose.options.pluralization;
658 }
659
660 if (!collection) {
661 collection = schema.get('collection') ||
662 utils.toCollectionName(name, _mongoose.pluralize());
663 }
664
665 const connection = options.connection || _mongoose.connection;
666 model = _mongoose.Model.compile(model || name, schema, collection, connection, _mongoose);
667 // Errors handled internally, so safe to ignore error
668 model.init().catch(function $modelInitNoop() {});
669
670 connection.emit('model', model);
671
672 if (schema._applyDiscriminators != null) {
673 for (const disc of schema._applyDiscriminators.keys()) {
674 const {
675 schema: discriminatorSchema,
676 options
677 } = schema._applyDiscriminators.get(disc);
678 model.discriminator(disc, discriminatorSchema, options);
679 }
680 }
681
682 applyEmbeddedDiscriminators(schema);
683
684 return model;
685};
686
687/**
688 * Removes the model named `name` from the default connection, if it exists.
689 * You can use this function to clean up any models you created in your tests to
690 * prevent OverwriteModelErrors.
691 *
692 * Equivalent to `mongoose.connection.deleteModel(name)`.
693 *
694 * #### Example:
695 *
696 * mongoose.model('User', new Schema({ name: String }));
697 * console.log(mongoose.model('User')); // Model object
698 * mongoose.deleteModel('User');
699 * console.log(mongoose.model('User')); // undefined
700 *
701 * // Usually useful in a Mocha `afterEach()` hook
702 * afterEach(function() {
703 * mongoose.deleteModel(/.+/); // Delete every model
704 * });
705 *
706 * @api public
707 * @param {String|RegExp} name if string, the name of the model to remove. If regexp, removes all models whose name matches the regexp.
708 * @return {Mongoose} this
709 */
710
711Mongoose.prototype.deleteModel = function(name) {
712 const _mongoose = this instanceof Mongoose ? this : mongoose;
713
714 _mongoose.connection.deleteModel(name);
715 delete _mongoose.models[name];
716 return _mongoose;
717};
718
719/**
720 * Returns an array of model names created on this instance of Mongoose.
721 *
722 * #### Note:
723 *
724 * _Does not include names of models created using `connection.model()`._
725 *
726 * @api public
727 * @return {Array}
728 */
729
730Mongoose.prototype.modelNames = function() {
731 const _mongoose = this instanceof Mongoose ? this : mongoose;
732
733 const names = Object.keys(_mongoose.models);
734 return names;
735};
736
737/**
738 * Applies global plugins to `schema`.
739 *
740 * @param {Schema} schema
741 * @api private
742 */
743
744Mongoose.prototype._applyPlugins = function(schema, options) {
745 const _mongoose = this instanceof Mongoose ? this : mongoose;
746
747 options = options || {};
748 options.applyPluginsToDiscriminators = _mongoose.options && _mongoose.options.applyPluginsToDiscriminators || false;
749 options.applyPluginsToChildSchemas = typeof (_mongoose.options && _mongoose.options.applyPluginsToChildSchemas) === 'boolean' ?
750 _mongoose.options.applyPluginsToChildSchemas :
751 true;
752 applyPlugins(schema, _mongoose.plugins, options, '$globalPluginsApplied');
753};
754
755/**
756 * Declares a global plugin executed on all Schemas.
757 *
758 * Equivalent to calling `.plugin(fn)` on each Schema you create.
759 *
760 * @param {Function} fn plugin callback
761 * @param {Object} [opts] optional options
762 * @return {Mongoose} this
763 * @see plugins https://mongoosejs.com/docs/plugins.html
764 * @api public
765 */
766
767Mongoose.prototype.plugin = function(fn, opts) {
768 const _mongoose = this instanceof Mongoose ? this : mongoose;
769
770 _mongoose.plugins.push([fn, opts]);
771 return _mongoose;
772};
773
774/**
775 * The Mongoose module's default connection. Equivalent to `mongoose.connections[0]`, see [`connections`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.connections).
776 *
777 * #### Example:
778 *
779 * const mongoose = require('mongoose');
780 * mongoose.connect(...);
781 * mongoose.connection.on('error', cb);
782 *
783 * This is the connection used by default for every model created using [mongoose.model](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.model()).
784 *
785 * To create a new connection, use [`createConnection()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.createConnection()).
786 *
787 * @memberOf Mongoose
788 * @instance
789 * @property {Connection} connection
790 * @api public
791 */
792
793Mongoose.prototype.__defineGetter__('connection', function() {
794 return this.connections[0];
795});
796
797Mongoose.prototype.__defineSetter__('connection', function(v) {
798 if (v instanceof this.__driver.Connection) {
799 this.connections[0] = v;
800 this.models = v.models;
801 }
802});
803
804/**
805 * An array containing all [connections](connection.html) associated with this
806 * Mongoose instance. By default, there is 1 connection. Calling
807 * [`createConnection()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.createConnection()) adds a connection
808 * to this array.
809 *
810 * #### Example:
811 *
812 * const mongoose = require('mongoose');
813 * mongoose.connections.length; // 1, just the default connection
814 * mongoose.connections[0] === mongoose.connection; // true
815 *
816 * mongoose.createConnection('mongodb://127.0.0.1:27017/test');
817 * mongoose.connections.length; // 2
818 *
819 * @memberOf Mongoose
820 * @instance
821 * @property {Array} connections
822 * @api public
823 */
824
825Mongoose.prototype.connections;
826
827/**
828 * An integer containing the value of the next connection id. Calling
829 * [`createConnection()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.createConnection()) increments
830 * this value.
831 *
832 * #### Example:
833 *
834 * const mongoose = require('mongoose');
835 * mongoose.createConnection(); // id `0`, `nextConnectionId` becomes `1`
836 * mongoose.createConnection(); // id `1`, `nextConnectionId` becomes `2`
837 * mongoose.connections[0].destroy() // Removes connection with id `0`
838 * mongoose.createConnection(); // id `2`, `nextConnectionId` becomes `3`
839 *
840 * @memberOf Mongoose
841 * @instance
842 * @property {Number} nextConnectionId
843 * @api private
844 */
845
846Mongoose.prototype.nextConnectionId;
847
848/**
849 * The Mongoose Aggregate constructor
850 *
851 * @method Aggregate
852 * @api public
853 */
854
855Mongoose.prototype.Aggregate = Aggregate;
856
857/**
858 * The Mongoose Collection constructor
859 *
860 * @memberOf Mongoose
861 * @instance
862 * @method Collection
863 * @api public
864 */
865
866Object.defineProperty(Mongoose.prototype, 'Collection', {
867 get: function() {
868 return this.__driver.Collection;
869 },
870 set: function(Collection) {
871 this.__driver.Collection = Collection;
872 }
873});
874
875/**
876 * The Mongoose [Connection](https://mongoosejs.com/docs/api/connection.html#Connection()) constructor
877 *
878 * @memberOf Mongoose
879 * @instance
880 * @method Connection
881 * @api public
882 */
883
884Object.defineProperty(Mongoose.prototype, 'Connection', {
885 get: function() {
886 return this.__driver.Connection;
887 },
888 set: function(Connection) {
889 if (Connection === this.__driver.Connection) {
890 return;
891 }
892
893 this.__driver.Connection = Connection;
894 }
895});
896
897/**
898 * The Mongoose version
899 *
900 * #### Example:
901 *
902 * console.log(mongoose.version); // '5.x.x'
903 *
904 * @property version
905 * @api public
906 */
907
908Mongoose.prototype.version = pkg.version;
909
910/**
911 * The Mongoose constructor
912 *
913 * The exports of the mongoose module is an instance of this class.
914 *
915 * #### Example:
916 *
917 * const mongoose = require('mongoose');
918 * const mongoose2 = new mongoose.Mongoose();
919 *
920 * @method Mongoose
921 * @api public
922 */
923
924Mongoose.prototype.Mongoose = Mongoose;
925
926/**
927 * The Mongoose [Schema](https://mongoosejs.com/docs/api/schema.html#Schema()) constructor
928 *
929 * #### Example:
930 *
931 * const mongoose = require('mongoose');
932 * const Schema = mongoose.Schema;
933 * const CatSchema = new Schema(..);
934 *
935 * @method Schema
936 * @api public
937 */
938
939Mongoose.prototype.Schema = Schema;
940
941/**
942 * The Mongoose [SchemaType](https://mongoosejs.com/docs/api/schematype.html#SchemaType()) constructor
943 *
944 * @method SchemaType
945 * @api public
946 */
947
948Mongoose.prototype.SchemaType = SchemaType;
949
950/**
951 * The various Mongoose SchemaTypes.
952 *
953 * #### Note:
954 *
955 * _Alias of mongoose.Schema.Types for backwards compatibility._
956 *
957 * @property SchemaTypes
958 * @see Schema.SchemaTypes https://mongoosejs.com/docs/schematypes.html
959 * @api public
960 */
961
962Mongoose.prototype.SchemaTypes = Schema.Types;
963
964/**
965 * The Mongoose [VirtualType](https://mongoosejs.com/docs/api/virtualtype.html#VirtualType()) constructor
966 *
967 * @method VirtualType
968 * @api public
969 */
970
971Mongoose.prototype.VirtualType = VirtualType;
972
973/**
974 * The various Mongoose Types.
975 *
976 * #### Example:
977 *
978 * const mongoose = require('mongoose');
979 * const array = mongoose.Types.Array;
980 *
981 * #### Types:
982 *
983 * - [Array](https://mongoosejs.com/docs/schematypes.html#arrays)
984 * - [Buffer](https://mongoosejs.com/docs/schematypes.html#buffers)
985 * - [Embedded](https://mongoosejs.com/docs/schematypes.html#schemas)
986 * - [DocumentArray](https://mongoosejs.com/docs/api/documentarraypath.html)
987 * - [Decimal128](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.Decimal128)
988 * - [ObjectId](https://mongoosejs.com/docs/schematypes.html#objectids)
989 * - [Map](https://mongoosejs.com/docs/schematypes.html#maps)
990 * - [Subdocument](https://mongoosejs.com/docs/schematypes.html#schemas)
991 *
992 * Using this exposed access to the `ObjectId` type, we can construct ids on demand.
993 *
994 * const ObjectId = mongoose.Types.ObjectId;
995 * const id1 = new ObjectId;
996 *
997 * @property Types
998 * @api public
999 */
1000
1001Mongoose.prototype.Types = Types;
1002
1003/**
1004 * The Mongoose [Query](https://mongoosejs.com/docs/api/query.html#Query()) constructor.
1005 *
1006 * @method Query
1007 * @api public
1008 */
1009
1010Mongoose.prototype.Query = Query;
1011
1012/**
1013 * The Mongoose [Model](https://mongoosejs.com/docs/api/model.html#Model()) constructor.
1014 *
1015 * @method Model
1016 * @api public
1017 */
1018
1019Mongoose.prototype.Model = Model;
1020
1021/**
1022 * The Mongoose [Document](https://mongoosejs.com/docs/api/document.html#Document()) constructor.
1023 *
1024 * @method Document
1025 * @api public
1026 */
1027
1028Mongoose.prototype.Document = Document;
1029
1030/**
1031 * The Mongoose DocumentProvider constructor. Mongoose users should not have to
1032 * use this directly
1033 *
1034 * @method DocumentProvider
1035 * @api public
1036 */
1037
1038Mongoose.prototype.DocumentProvider = require('./documentProvider');
1039
1040/**
1041 * The Mongoose ObjectId [SchemaType](https://mongoosejs.com/docs/schematypes.html). Used for
1042 * declaring paths in your schema that should be
1043 * [MongoDB ObjectIds](https://www.mongodb.com/docs/manual/reference/method/ObjectId/).
1044 * Do not use this to create a new ObjectId instance, use `mongoose.Types.ObjectId`
1045 * instead.
1046 *
1047 * #### Example:
1048 *
1049 * const childSchema = new Schema({ parentId: mongoose.ObjectId });
1050 *
1051 * @property ObjectId
1052 * @api public
1053 */
1054
1055Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
1056
1057/**
1058 * Returns true if Mongoose can cast the given value to an ObjectId, or
1059 * false otherwise.
1060 *
1061 * #### Example:
1062 *
1063 * mongoose.isValidObjectId(new mongoose.Types.ObjectId()); // true
1064 * mongoose.isValidObjectId('0123456789ab'); // true
1065 * mongoose.isValidObjectId(6); // true
1066 * mongoose.isValidObjectId(new User({ name: 'test' })); // true
1067 *
1068 * mongoose.isValidObjectId({ test: 42 }); // false
1069 *
1070 * @method isValidObjectId
1071 * @param {Any} v
1072 * @returns {boolean} true if `v` is something Mongoose can coerce to an ObjectId
1073 * @api public
1074 */
1075
1076Mongoose.prototype.isValidObjectId = function(v) {
1077 const _mongoose = this instanceof Mongoose ? this : mongoose;
1078 return _mongoose.Types.ObjectId.isValid(v);
1079};
1080
1081/**
1082 * Returns true if the given value is a Mongoose ObjectId (using `instanceof`) or if the
1083 * given value is a 24 character hex string, which is the most commonly used string representation
1084 * of an ObjectId.
1085 *
1086 * This function is similar to `isValidObjectId()`, but considerably more strict, because
1087 * `isValidObjectId()` will return `true` for _any_ value that Mongoose can convert to an
1088 * ObjectId. That includes Mongoose documents, any string of length 12, and any number.
1089 * `isObjectIdOrHexString()` returns true only for `ObjectId` instances or 24 character hex
1090 * strings, and will return false for numbers, documents, and strings of length 12.
1091 *
1092 * #### Example:
1093 *
1094 * mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()); // true
1095 * mongoose.isObjectIdOrHexString('62261a65d66c6be0a63c051f'); // true
1096 *
1097 * mongoose.isObjectIdOrHexString('0123456789ab'); // false
1098 * mongoose.isObjectIdOrHexString(6); // false
1099 * mongoose.isObjectIdOrHexString(new User({ name: 'test' })); // false
1100 * mongoose.isObjectIdOrHexString({ test: 42 }); // false
1101 *
1102 * @method isObjectIdOrHexString
1103 * @param {Any} v
1104 * @returns {boolean} true if `v` is an ObjectId instance _or_ a 24 char hex string
1105 * @api public
1106 */
1107
1108Mongoose.prototype.isObjectIdOrHexString = function(v) {
1109 return isBsonType(v, 'ObjectId') || (typeof v === 'string' && objectIdHexRegexp.test(v));
1110};
1111
1112/**
1113 *
1114 * Syncs all the indexes for the models registered with this connection.
1115 *
1116 * @param {Object} options
1117 * @param {Boolean} options.continueOnError `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.
1118 * @return {Promise} Returns a Promise, when the Promise resolves the value is a list of the dropped indexes.
1119 */
1120Mongoose.prototype.syncIndexes = function(options) {
1121 const _mongoose = this instanceof Mongoose ? this : mongoose;
1122 return _mongoose.connection.syncIndexes(options);
1123};
1124
1125/**
1126 * The Mongoose Decimal128 [SchemaType](https://mongoosejs.com/docs/schematypes.html). Used for
1127 * declaring paths in your schema that should be
1128 * [128-bit decimal floating points](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-decimal.html).
1129 * Do not use this to create a new Decimal128 instance, use `mongoose.Types.Decimal128`
1130 * instead.
1131 *
1132 * #### Example:
1133 *
1134 * const vehicleSchema = new Schema({ fuelLevel: mongoose.Decimal128 });
1135 *
1136 * @property Decimal128
1137 * @api public
1138 */
1139
1140Mongoose.prototype.Decimal128 = SchemaTypes.Decimal128;
1141
1142/**
1143 * The Mongoose Mixed [SchemaType](https://mongoosejs.com/docs/schematypes.html). Used for
1144 * declaring paths in your schema that Mongoose's change tracking, casting,
1145 * and validation should ignore.
1146 *
1147 * #### Example:
1148 *
1149 * const schema = new Schema({ arbitrary: mongoose.Mixed });
1150 *
1151 * @property Mixed
1152 * @api public
1153 */
1154
1155Mongoose.prototype.Mixed = SchemaTypes.Mixed;
1156
1157/**
1158 * The Mongoose Date [SchemaType](https://mongoosejs.com/docs/schematypes.html).
1159 *
1160 * #### Example:
1161 *
1162 * const schema = new Schema({ test: Date });
1163 * schema.path('test') instanceof mongoose.Date; // true
1164 *
1165 * @property Date
1166 * @api public
1167 */
1168
1169Mongoose.prototype.Date = SchemaTypes.Date;
1170
1171/**
1172 * The Mongoose Number [SchemaType](https://mongoosejs.com/docs/schematypes.html). Used for
1173 * declaring paths in your schema that Mongoose should cast to numbers.
1174 *
1175 * #### Example:
1176 *
1177 * const schema = new Schema({ num: mongoose.Number });
1178 * // Equivalent to:
1179 * const schema = new Schema({ num: 'number' });
1180 *
1181 * @property Number
1182 * @api public
1183 */
1184
1185Mongoose.prototype.Number = SchemaTypes.Number;
1186
1187/**
1188 * The [MongooseError](https://mongoosejs.com/docs/api/error.html#Error()) constructor.
1189 *
1190 * @method Error
1191 * @api public
1192 */
1193
1194Mongoose.prototype.Error = require('./error/index');
1195Mongoose.prototype.MongooseError = require('./error/mongooseError');
1196
1197/**
1198 * Mongoose uses this function to get the current time when setting
1199 * [timestamps](https://mongoosejs.com/docs/guide.html#timestamps). You may stub out this function
1200 * using a tool like [Sinon](https://www.npmjs.com/package/sinon) for testing.
1201 *
1202 * @method now
1203 * @returns Date the current time
1204 * @api public
1205 */
1206
1207Mongoose.prototype.now = function now() { return new Date(); };
1208
1209/**
1210 * The Mongoose CastError constructor
1211 *
1212 * @method CastError
1213 * @param {String} type The name of the type
1214 * @param {Any} value The value that failed to cast
1215 * @param {String} path The path `a.b.c` in the doc where this cast error occurred
1216 * @param {Error} [reason] The original error that was thrown
1217 * @api public
1218 */
1219
1220Mongoose.prototype.CastError = require('./error/cast');
1221
1222/**
1223 * The constructor used for schematype options
1224 *
1225 * @method SchemaTypeOptions
1226 * @api public
1227 */
1228
1229Mongoose.prototype.SchemaTypeOptions = require('./options/schemaTypeOptions');
1230
1231/**
1232 * The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses.
1233 *
1234 * @property mquery
1235 * @api public
1236 */
1237
1238Mongoose.prototype.mquery = require('mquery');
1239
1240/**
1241 * Sanitizes query filters against [query selector injection attacks](https://thecodebarbarian.com/2014/09/04/defending-against-query-selector-injection-attacks.html)
1242 * by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
1243 *
1244 * ```javascript
1245 * const obj = { username: 'val', pwd: { $ne: null } };
1246 * sanitizeFilter(obj);
1247 * obj; // { username: 'val', pwd: { $eq: { $ne: null } } });
1248 * ```
1249 *
1250 * @method sanitizeFilter
1251 * @param {Object} filter
1252 * @returns Object the sanitized object
1253 * @api public
1254 */
1255
1256Mongoose.prototype.sanitizeFilter = sanitizeFilter;
1257
1258/**
1259 * Tells `sanitizeFilter()` to skip the given object when filtering out potential [query selector injection attacks](https://thecodebarbarian.com/2014/09/04/defending-against-query-selector-injection-attacks.html).
1260 * Use this method when you have a known query selector that you want to use.
1261 *
1262 * ```javascript
1263 * const obj = { username: 'val', pwd: trusted({ $type: 'string', $eq: 'my secret' }) };
1264 * sanitizeFilter(obj);
1265 *
1266 * // Note that `sanitizeFilter()` did not add `$eq` around `$type`.
1267 * obj; // { username: 'val', pwd: { $type: 'string', $eq: 'my secret' } });
1268 * ```
1269 *
1270 * @method trusted
1271 * @param {Object} obj
1272 * @returns Object the passed in object
1273 * @api public
1274 */
1275
1276Mongoose.prototype.trusted = trusted;
1277
1278/**
1279 * Use this function in `pre()` middleware to skip calling the wrapped function.
1280 *
1281 * #### Example:
1282 *
1283 * schema.pre('save', function() {
1284 * // Will skip executing `save()`, but will execute post hooks as if
1285 * // `save()` had executed with the result `{ matchedCount: 0 }`
1286 * return mongoose.skipMiddlewareFunction({ matchedCount: 0 });
1287 * });
1288 *
1289 * @method skipMiddlewareFunction
1290 * @param {any} result
1291 * @api public
1292 */
1293
1294Mongoose.prototype.skipMiddlewareFunction = Kareem.skipWrappedFunction;
1295
1296/**
1297 * Use this function in `post()` middleware to replace the result
1298 *
1299 * #### Example:
1300 *
1301 * schema.post('find', function(res) {
1302 * // Normally you have to modify `res` in place. But with
1303 * // `overwriteMiddlewarResult()`, you can make `find()` return a
1304 * // completely different value.
1305 * return mongoose.overwriteMiddlewareResult(res.filter(doc => !doc.isDeleted));
1306 * });
1307 *
1308 * @method overwriteMiddlewareResult
1309 * @param {any} result
1310 * @api public
1311 */
1312
1313Mongoose.prototype.overwriteMiddlewareResult = Kareem.overwriteResult;
1314
1315/**
1316 * Takes in an object and deletes any keys from the object whose values
1317 * are strictly equal to `undefined`.
1318 * This function is useful for query filters because Mongoose treats
1319 * `TestModel.find({ name: undefined })` as `TestModel.find({ name: null })`.
1320 *
1321 * #### Example:
1322 *
1323 * const filter = { name: 'John', age: undefined, status: 'active' };
1324 * mongoose.omitUndefined(filter); // { name: 'John', status: 'active' }
1325 * filter; // { name: 'John', status: 'active' }
1326 *
1327 * await UserModel.findOne(mongoose.omitUndefined(filter));
1328 *
1329 * @method omitUndefined
1330 * @param {Object} [val] the object to remove undefined keys from
1331 * @returns {Object} the object passed in
1332 * @api public
1333 */
1334
1335Mongoose.prototype.omitUndefined = require('./helpers/omitUndefined');
1336
1337/*!
1338 * Create a new default connection (`mongoose.connection`) for a Mongoose instance.
1339 * No-op if there is already a default connection.
1340 */
1341
1342function _createDefaultConnection(mongoose) {
1343 if (mongoose.connection) {
1344 return;
1345 }
1346 const conn = mongoose.createConnection(); // default connection
1347 conn[defaultConnectionSymbol] = true;
1348 conn.models = mongoose.models;
1349}
1350
1351/**
1352 * The exports object is an instance of Mongoose.
1353 *
1354 * @api private
1355 */
1356
1357const mongoose = module.exports = exports = new Mongoose({
1358 [defaultMongooseSymbol]: true
1359});