Source: lib/mongo_client.js

  1. 'use strict';
  2. const ChangeStream = require('./change_stream');
  3. const Db = require('./db');
  4. const EventEmitter = require('events').EventEmitter;
  5. const executeOperation = require('./operations/execute_operation');
  6. const inherits = require('util').inherits;
  7. const MongoError = require('./core').MongoError;
  8. const deprecate = require('util').deprecate;
  9. const WriteConcern = require('./write_concern');
  10. const MongoDBNamespace = require('./utils').MongoDBNamespace;
  11. const ReadPreference = require('./core/topologies/read_preference');
  12. // Operations
  13. const ConnectOperation = require('./operations/connect');
  14. const CloseOperation = require('./operations/close');
  15. /**
  16. * @fileOverview The **MongoClient** class is a class that allows for making Connections to MongoDB.
  17. *
  18. * @example
  19. * // Connect using a MongoClient instance
  20. * const MongoClient = require('mongodb').MongoClient;
  21. * const test = require('assert');
  22. * // Connection url
  23. * const url = 'mongodb://localhost:27017';
  24. * // Database Name
  25. * const dbName = 'test';
  26. * // Connect using MongoClient
  27. * const mongoClient = new MongoClient(url);
  28. * mongoClient.connect(function(err, client) {
  29. * const db = client.db(dbName);
  30. * client.close();
  31. * });
  32. *
  33. * @example
  34. * // Connect using the MongoClient.connect static method
  35. * const MongoClient = require('mongodb').MongoClient;
  36. * const test = require('assert');
  37. * // Connection url
  38. * const url = 'mongodb://localhost:27017';
  39. * // Database Name
  40. * const dbName = 'test';
  41. * // Connect using MongoClient
  42. * MongoClient.connect(url, function(err, client) {
  43. * const db = client.db(dbName);
  44. * client.close();
  45. * });
  46. */
  47. /**
  48. * A string specifying the level of a ReadConcern
  49. * @typedef {'local'|'available'|'majority'|'linearizable'|'snapshot'} ReadConcernLevel
  50. * @see https://www.mongodb.com/docs/manual/reference/read-concern/index.html#read-concern-levels
  51. */
  52. /**
  53. * Configuration options for a automatic client encryption.
  54. *
  55. * **NOTE**: Support for client side encryption is in beta. Backwards-breaking changes may be made before the final release.
  56. *
  57. * @typedef {Object} AutoEncryptionOptions
  58. * @property {MongoClient} [keyVaultClient] A `MongoClient` used to fetch keys from a key vault
  59. * @property {string} [keyVaultNamespace] The namespace where keys are stored in the key vault
  60. * @property {object} [kmsProviders] Provider details for the desired Key Management Service to use for encryption
  61. * @property {object} [kmsProviders.aws] Optional settings for the AWS KMS provider
  62. * @property {string} [kmsProviders.aws.accessKeyId] The access key used for the AWS KMS provider
  63. * @property {string} [kmsProviders.aws.secretAccessKey] The secret access key used for the AWS KMS provider
  64. * @property {object} [kmsProviders.local] Optional settings for the local KMS provider
  65. * @property {string} [kmsProviders.local.key] The master key used to encrypt/decrypt data keys
  66. * @property {object} [schemaMap] A map of namespaces to a local JSON schema for encryption
  67. * @property {boolean} [bypassAutoEncryption] Allows the user to bypass auto encryption, maintaining implicit decryption
  68. * @property {object} [extraOptions] Extra options related to the mongocryptd process
  69. * @property {string} [extraOptions.mongocryptURI] A local process the driver communicates with to determine how to encrypt values in a command. Defaults to "mongodb://%2Fvar%2Fmongocryptd.sock" if domain sockets are available or "mongodb://localhost:27020" otherwise
  70. * @property {boolean} [extraOptions.mongocryptdBypassSpawn=false] If true, autoEncryption will not attempt to spawn a mongocryptd before connecting
  71. * @property {string} [extraOptions.mongocryptdSpawnPath] The path to the mongocryptd executable on the system
  72. * @property {string[]} [extraOptions.mongocryptdSpawnArgs] Command line arguments to use when auto-spawning a mongocryptd
  73. */
  74. /**
  75. * Configuration options for drivers wrapping the node driver.
  76. *
  77. * @typedef {Object} DriverInfoOptions
  78. * @property {string} [name] The name of the driver
  79. * @property {string} [version] The version of the driver
  80. * @property {string} [platform] Optional platform information
  81. */
  82. /**
  83. * Creates a new MongoClient instance
  84. * @class
  85. * @param {string} url The connection URI string
  86. * @param {object} [options] Optional settings
  87. * @param {number} [options.poolSize=5] The maximum size of the individual server pool
  88. * @param {boolean} [options.ssl=false] Enable SSL connection.
  89. * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
  90. * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
  91. * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer
  92. * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer
  93. * @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
  94. * @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer
  95. * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
  96. * @param {boolean} [options.noDelay=true] TCP Connection no delay
  97. * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
  98. * @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
  99. * @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
  100. * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
  101. * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
  102. * @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
  103. * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
  104. * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
  105. * @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
  106. * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
  107. * @param {string} [options.replicaSet=undefined] The Replicaset set name
  108. * @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
  109. * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
  110. * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
  111. * @param {string} [options.authSource=undefined] Define the database to authenticate against
  112. * @param {(number|string)} [options.w] The write concern
  113. * @param {number} [options.wtimeout] The write concern timeout
  114. * @param {boolean} [options.j=false] Specify a journal write concern
  115. * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
  116. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
  117. * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
  118. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers
  119. * @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
  120. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
  121. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
  122. * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
  123. * @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
  124. * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
  125. * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
  126. * @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
  127. * @param {object} [options.logger=undefined] Custom logger object
  128. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
  129. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
  130. * @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
  131. * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
  132. * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function
  133. * @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
  134. * @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
  135. * @param {string} [options.auth.user=undefined] The username for auth
  136. * @param {string} [options.auth.password=undefined] The password for auth
  137. * @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
  138. * @param {object} [options.compression] Type of compression to use: snappy or zlib
  139. * @param {boolean} [options.fsync=false] Specify a file sync write concern
  140. * @param {array} [options.readPreferenceTags] Read preference tags
  141. * @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
  142. * @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
  143. * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this client
  144. * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
  145. * @param {boolean} [options.useNewUrlParser=true] Determines whether or not to use the new url parser. Enables the new, spec-compliant, url parser shipped in the core driver. This url parser fixes a number of problems with the original parser, and aims to outright replace that parser in the near future. Defaults to true, and must be explicitly set to false to use the legacy url parser.
  146. * @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
  147. * @param {AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
  148. * @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
  149. * @param {MongoClient~connectCallback} [callback] The command result callback
  150. * @return {MongoClient} a MongoClient instance
  151. */
  152. function MongoClient(url, options) {
  153. if (!(this instanceof MongoClient)) return new MongoClient(url, options);
  154. // Set up event emitter
  155. EventEmitter.call(this);
  156. // The internal state
  157. this.s = {
  158. url: url,
  159. options: options || {},
  160. promiseLibrary: null,
  161. dbCache: new Map(),
  162. sessions: new Set(),
  163. writeConcern: WriteConcern.fromOptions(options),
  164. namespace: new MongoDBNamespace('admin')
  165. };
  166. // Get the promiseLibrary
  167. const promiseLibrary = this.s.options.promiseLibrary || Promise;
  168. // Add the promise to the internal state
  169. this.s.promiseLibrary = promiseLibrary;
  170. }
  171. /**
  172. * @ignore
  173. */
  174. inherits(MongoClient, EventEmitter);
  175. Object.defineProperty(MongoClient.prototype, 'writeConcern', {
  176. enumerable: true,
  177. get: function() {
  178. return this.s.writeConcern;
  179. }
  180. });
  181. Object.defineProperty(MongoClient.prototype, 'readPreference', {
  182. enumerable: true,
  183. get: function() {
  184. return ReadPreference.primary;
  185. }
  186. });
  187. /**
  188. * The callback format for results
  189. * @callback MongoClient~connectCallback
  190. * @param {MongoError} error An error instance representing the error during the execution.
  191. * @param {MongoClient} client The connected client.
  192. */
  193. /**
  194. * Connect to MongoDB using a url as documented at
  195. *
  196. * docs.mongodb.org/manual/reference/connection-string/
  197. *
  198. * Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
  199. *
  200. * @method
  201. * @param {MongoClient~connectCallback} [callback] The command result callback
  202. * @return {Promise<MongoClient>} returns Promise if no callback passed
  203. */
  204. MongoClient.prototype.connect = function(callback) {
  205. if (typeof callback === 'string') {
  206. throw new TypeError('`connect` only accepts a callback');
  207. }
  208. const operation = new ConnectOperation(this);
  209. return executeOperation(this, operation, callback);
  210. };
  211. MongoClient.prototype.logout = deprecate(function(options, callback) {
  212. if (typeof options === 'function') (callback = options), (options = {});
  213. if (typeof callback === 'function') callback(null, true);
  214. }, 'Multiple authentication is prohibited on a connected client, please only authenticate once per MongoClient');
  215. /**
  216. * Close the db and its underlying connections
  217. * @method
  218. * @param {boolean} [force=false] Force close, emitting no events
  219. * @param {Db~noResultCallback} [callback] The result callback
  220. * @return {Promise} returns Promise if no callback passed
  221. */
  222. MongoClient.prototype.close = function(force, callback) {
  223. if (typeof force === 'function') (callback = force), (force = false);
  224. const operation = new CloseOperation(this, force);
  225. return executeOperation(this, operation, callback);
  226. };
  227. /**
  228. * Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
  229. * related in a parent-child relationship to the original instance so that events are correctly emitted on child
  230. * db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
  231. * You can control these behaviors with the options noListener and returnNonCachedInstance.
  232. *
  233. * @method
  234. * @param {string} [dbName] The name of the database we want to use. If not provided, use database name from connection string.
  235. * @param {object} [options] Optional settings.
  236. * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
  237. * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
  238. * @return {Db}
  239. */
  240. MongoClient.prototype.db = function(dbName, options) {
  241. options = options || {};
  242. // Default to db from connection string if not provided
  243. if (!dbName) {
  244. dbName = this.s.options.dbName;
  245. }
  246. // Copy the options and add out internal override of the not shared flag
  247. const finalOptions = Object.assign({}, this.s.options, options);
  248. // Do we have the db in the cache already
  249. if (this.s.dbCache.has(dbName) && finalOptions.returnNonCachedInstance !== true) {
  250. return this.s.dbCache.get(dbName);
  251. }
  252. // Add promiseLibrary
  253. finalOptions.promiseLibrary = this.s.promiseLibrary;
  254. // If no topology throw an error message
  255. if (!this.topology) {
  256. throw new MongoError('MongoClient must be connected before calling MongoClient.prototype.db');
  257. }
  258. // Return the db object
  259. const db = new Db(dbName, this.topology, finalOptions);
  260. // Add the db to the cache
  261. this.s.dbCache.set(dbName, db);
  262. // Return the database
  263. return db;
  264. };
  265. /**
  266. * Check if MongoClient is connected
  267. *
  268. * @method
  269. * @param {object} [options] Optional settings.
  270. * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
  271. * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
  272. * @return {boolean}
  273. */
  274. MongoClient.prototype.isConnected = function(options) {
  275. options = options || {};
  276. if (!this.topology) return false;
  277. return this.topology.isConnected(options);
  278. };
  279. /**
  280. * Connect to MongoDB using a url as documented at
  281. *
  282. * docs.mongodb.org/manual/reference/connection-string/
  283. *
  284. * Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
  285. *
  286. * @method
  287. * @static
  288. * @param {string} url The connection URI string
  289. * @param {object} [options] Optional settings
  290. * @param {number} [options.poolSize=5] The maximum size of the individual server pool
  291. * @param {boolean} [options.ssl=false] Enable SSL connection.
  292. * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
  293. * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
  294. * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer
  295. * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer
  296. * @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
  297. * @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer
  298. * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
  299. * @param {boolean} [options.noDelay=true] TCP Connection no delay
  300. * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
  301. * @param {boolean} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
  302. * @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
  303. * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
  304. * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
  305. * @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
  306. * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
  307. * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
  308. * @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
  309. * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
  310. * @param {string} [options.replicaSet=undefined] The Replicaset set name
  311. * @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
  312. * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
  313. * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
  314. * @param {string} [options.authSource=undefined] Define the database to authenticate against
  315. * @param {(number|string)} [options.w] The write concern
  316. * @param {number} [options.wtimeout] The write concern timeout
  317. * @param {boolean} [options.j=false] Specify a journal write concern
  318. * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
  319. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
  320. * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
  321. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers
  322. * @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
  323. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
  324. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
  325. * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
  326. * @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
  327. * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
  328. * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
  329. * @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
  330. * @param {object} [options.logger=undefined] Custom logger object
  331. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
  332. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
  333. * @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
  334. * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
  335. * @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function
  336. * @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
  337. * @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
  338. * @param {string} [options.auth.user=undefined] The username for auth
  339. * @param {string} [options.auth.password=undefined] The password for auth
  340. * @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
  341. * @param {object} [options.compression] Type of compression to use: snappy or zlib
  342. * @param {boolean} [options.fsync=false] Specify a file sync write concern
  343. * @param {array} [options.readPreferenceTags] Read preference tags
  344. * @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
  345. * @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
  346. * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
  347. * @param {MongoClient~connectCallback} [callback] The command result callback
  348. * @return {Promise<MongoClient>} returns Promise if no callback passed
  349. */
  350. MongoClient.connect = function(url, options, callback) {
  351. const args = Array.prototype.slice.call(arguments, 1);
  352. callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
  353. options = args.length ? args.shift() : null;
  354. options = options || {};
  355. // Create client
  356. const mongoClient = new MongoClient(url, options);
  357. // Execute the connect method
  358. return mongoClient.connect(callback);
  359. };
  360. /**
  361. * Starts a new session on the server
  362. *
  363. * @param {SessionOptions} [options] optional settings for a driver session
  364. * @return {ClientSession} the newly established session
  365. */
  366. MongoClient.prototype.startSession = function(options) {
  367. options = Object.assign({ explicit: true }, options);
  368. if (!this.topology) {
  369. throw new MongoError('Must connect to a server before calling this method');
  370. }
  371. if (!this.topology.hasSessionSupport()) {
  372. throw new MongoError('Current topology does not support sessions');
  373. }
  374. return this.topology.startSession(options, this.s.options);
  375. };
  376. /**
  377. * Runs a given operation with an implicitly created session. The lifetime of the session
  378. * will be handled without the need for user interaction.
  379. *
  380. * NOTE: presently the operation MUST return a Promise (either explicit or implicity as an async function)
  381. *
  382. * @param {Object} [options] Optional settings to be appled to implicitly created session
  383. * @param {Function} operation An operation to execute with an implicitly created session. The signature of this MUST be `(session) => {}`
  384. * @return {Promise}
  385. */
  386. MongoClient.prototype.withSession = function(options, operation) {
  387. if (typeof options === 'function') (operation = options), (options = undefined);
  388. const session = this.startSession(options);
  389. let cleanupHandler = (err, result, opts) => {
  390. // prevent multiple calls to cleanupHandler
  391. cleanupHandler = () => {
  392. throw new ReferenceError('cleanupHandler was called too many times');
  393. };
  394. opts = Object.assign({ throw: true }, opts);
  395. session.endSession();
  396. if (err) {
  397. if (opts.throw) throw err;
  398. return Promise.reject(err);
  399. }
  400. };
  401. try {
  402. const result = operation(session);
  403. return Promise.resolve(result)
  404. .then(result => cleanupHandler(null, result))
  405. .catch(err => cleanupHandler(err, null, { throw: true }));
  406. } catch (err) {
  407. return cleanupHandler(err, null, { throw: false });
  408. }
  409. };
  410. /**
  411. * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this cluster. Will ignore all changes to system collections, as well as the local, admin,
  412. * and config databases.
  413. * @method
  414. * @since 3.1.0
  415. * @param {Array} [pipeline] An array of {@link https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents. This allows for filtering (using $match) and manipulating the change stream documents.
  416. * @param {object} [options] Optional settings
  417. * @param {string} [options.fullDocument='default'] Allowed values: ‘default’, ‘updateLookup’. When set to ‘updateLookup’, the change stream will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
  418. * @param {object} [options.resumeAfter] Specifies the logical starting point for the new change stream. This should be the _id field from a previously returned change stream document.
  419. * @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
  420. * @param {number} [options.batchSize=1000] The number of documents to return per batch. See {@link https://www.mongodb.com/docs/manual/reference/command/aggregate|aggregation documentation}.
  421. * @param {object} [options.collation] Specify collation settings for operation. See {@link https://www.mongodb.com/docs/manual/reference/command/aggregate|aggregation documentation}.
  422. * @param {ReadPreference} [options.readPreference] The read preference. See {@link https://www.mongodb.com/docs/manual/reference/read-preference|read preference documentation}.
  423. * @param {Timestamp} [options.startAtOperationTime] receive change events that occur after the specified timestamp
  424. * @param {ClientSession} [options.session] optional session to use for this operation
  425. * @return {ChangeStream} a ChangeStream instance.
  426. */
  427. MongoClient.prototype.watch = function(pipeline, options) {
  428. pipeline = pipeline || [];
  429. options = options || {};
  430. // Allow optionally not specifying a pipeline
  431. if (!Array.isArray(pipeline)) {
  432. options = pipeline;
  433. pipeline = [];
  434. }
  435. return new ChangeStream(this, pipeline, options);
  436. };
  437. /**
  438. * Return the mongo client logger
  439. * @method
  440. * @return {Logger} return the mongo client logger
  441. * @ignore
  442. */
  443. MongoClient.prototype.getLogger = function() {
  444. return this.s.options.logger;
  445. };
  446. module.exports = MongoClient;