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 drivers wrapping the node driver.
  54. *
  55. * @typedef {Object} DriverInfoOptions
  56. * @property {string} [name] The name of the driver
  57. * @property {string} [version] The version of the driver
  58. * @property {string} [platform] Optional platform information
  59. */
  60. /**
  61. * Configuration options for drivers wrapping the node driver.
  62. *
  63. * @typedef {Object} DriverInfoOptions
  64. * @property {string} [name] The name of the driver
  65. * @property {string} [version] The version of the driver
  66. * @property {string} [platform] Optional platform information
  67. */
  68. /**
  69. * Creates a new MongoClient instance
  70. * @class
  71. * @param {string} url The connection URI string
  72. * @param {object} [options] Optional settings
  73. * @param {number} [options.poolSize=5] The maximum size of the individual server pool
  74. * @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
  75. * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority
  76. * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
  77. * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
  78. * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
  79. * @param {string} [options.sslPass=undefined] SSL Certificate pass phrase *deprecated* use `tls` variants
  80. * @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
  81. * @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. *deprecated* use `tls` variants
  82. * @param {boolean} [options.tls=false] Enable TLS connections
  83. * @param {boolean} [options.tlsinsecure=false] Relax TLS constraints, disabling validation
  84. * @param {string} [options.tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
  85. * @param {string} [options.tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
  86. * @param {string} [options.tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
  87. * @param {boolean} [options.tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
  88. * @param {boolean} [options.tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
  89. * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
  90. * @param {boolean} [options.noDelay=true] TCP Connection no delay
  91. * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
  92. * @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
  93. * @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
  94. * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
  95. * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
  96. * @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
  97. * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
  98. * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
  99. * @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
  100. * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
  101. * @param {string} [options.replicaSet=undefined] The Replicaset set name
  102. * @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
  103. * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
  104. * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
  105. * @param {string} [options.authSource=undefined] Define the database to authenticate against
  106. * @param {(number|string)} [options.w] The write concern
  107. * @param {number} [options.wtimeout] The write concern timeout
  108. * @param {boolean} [options.j=false] Specify a journal write concern
  109. * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
  110. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
  111. * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
  112. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers
  113. * @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
  114. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
  115. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
  116. * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
  117. * @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
  118. * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
  119. * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
  120. * @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
  121. * @param {object} [options.logger=undefined] Custom logger object
  122. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
  123. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
  124. * @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
  125. * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
  126. * @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
  127. * @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
  128. * @param {string} [options.auth.user=undefined] The username for auth
  129. * @param {string} [options.auth.password=undefined] The password for auth
  130. * @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, or SCRAM-SHA-1
  131. * @param {object} [options.compression] Type of compression to use: snappy or zlib
  132. * @param {boolean} [options.fsync=false] Specify a file sync write concern
  133. * @param {array} [options.readPreferenceTags] Read preference tags
  134. * @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
  135. * @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
  136. * @param {boolean} [options.monitorCommands=false] Enable command monitoring for this client
  137. * @param {number} [options.minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
  138. * @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.
  139. * @param {boolean} [options.useUnifiedTopology] Enables the new unified topology layer
  140. * @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
  141. * @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
  142. * @param {MongoClient~connectCallback} [callback] The command result callback
  143. * @return {MongoClient} a MongoClient instance
  144. */
  145. function MongoClient(url, options) {
  146. if (!(this instanceof MongoClient)) return new MongoClient(url, options);
  147. // Set up event emitter
  148. EventEmitter.call(this);
  149. // The internal state
  150. this.s = {
  151. url: url,
  152. options: options || {},
  153. promiseLibrary: null,
  154. dbCache: new Map(),
  155. sessions: new Set(),
  156. writeConcern: WriteConcern.fromOptions(options),
  157. namespace: new MongoDBNamespace('admin')
  158. };
  159. // Get the promiseLibrary
  160. const promiseLibrary = this.s.options.promiseLibrary || Promise;
  161. // Add the promise to the internal state
  162. this.s.promiseLibrary = promiseLibrary;
  163. }
  164. /**
  165. * @ignore
  166. */
  167. inherits(MongoClient, EventEmitter);
  168. Object.defineProperty(MongoClient.prototype, 'writeConcern', {
  169. enumerable: true,
  170. get: function() {
  171. return this.s.writeConcern;
  172. }
  173. });
  174. Object.defineProperty(MongoClient.prototype, 'readPreference', {
  175. enumerable: true,
  176. get: function() {
  177. return ReadPreference.primary;
  178. }
  179. });
  180. /**
  181. * The callback format for results
  182. * @callback MongoClient~connectCallback
  183. * @param {MongoError} error An error instance representing the error during the execution.
  184. * @param {MongoClient} client The connected client.
  185. */
  186. /**
  187. * Connect to MongoDB using a url as documented at
  188. *
  189. * docs.mongodb.org/manual/reference/connection-string/
  190. *
  191. * Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
  192. *
  193. * @method
  194. * @param {MongoClient~connectCallback} [callback] The command result callback
  195. * @return {Promise<MongoClient>} returns Promise if no callback passed
  196. */
  197. MongoClient.prototype.connect = function(callback) {
  198. if (typeof callback === 'string') {
  199. throw new TypeError('`connect` only accepts a callback');
  200. }
  201. const operation = new ConnectOperation(this);
  202. return executeOperation(this, operation, callback);
  203. };
  204. MongoClient.prototype.logout = deprecate(function(options, callback) {
  205. if (typeof options === 'function') (callback = options), (options = {});
  206. if (typeof callback === 'function') callback(null, true);
  207. }, 'Multiple authentication is prohibited on a connected client, please only authenticate once per MongoClient');
  208. /**
  209. * Close the db and its underlying connections
  210. * @method
  211. * @param {boolean} [force=false] Force close, emitting no events
  212. * @param {Db~noResultCallback} [callback] The result callback
  213. * @return {Promise} returns Promise if no callback passed
  214. */
  215. MongoClient.prototype.close = function(force, callback) {
  216. if (typeof force === 'function') (callback = force), (force = false);
  217. const operation = new CloseOperation(this, force);
  218. return executeOperation(this, operation, callback);
  219. };
  220. /**
  221. * Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
  222. * related in a parent-child relationship to the original instance so that events are correctly emitted on child
  223. * db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
  224. * You can control these behaviors with the options noListener and returnNonCachedInstance.
  225. *
  226. * @method
  227. * @param {string} [dbName] The name of the database we want to use. If not provided, use database name from connection string.
  228. * @param {object} [options] Optional settings.
  229. * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
  230. * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
  231. * @return {Db}
  232. */
  233. MongoClient.prototype.db = function(dbName, options) {
  234. options = options || {};
  235. // Default to db from connection string if not provided
  236. if (!dbName) {
  237. dbName = this.s.options.dbName;
  238. }
  239. // Copy the options and add out internal override of the not shared flag
  240. const finalOptions = Object.assign({}, this.s.options, options);
  241. // Do we have the db in the cache already
  242. if (this.s.dbCache.has(dbName) && finalOptions.returnNonCachedInstance !== true) {
  243. return this.s.dbCache.get(dbName);
  244. }
  245. // Add promiseLibrary
  246. finalOptions.promiseLibrary = this.s.promiseLibrary;
  247. // If no topology throw an error message
  248. if (!this.topology) {
  249. throw new MongoError('MongoClient must be connected before calling MongoClient.prototype.db');
  250. }
  251. // Return the db object
  252. const db = new Db(dbName, this.topology, finalOptions);
  253. // Add the db to the cache
  254. this.s.dbCache.set(dbName, db);
  255. // Return the database
  256. return db;
  257. };
  258. /**
  259. * Check if MongoClient is connected
  260. *
  261. * @method
  262. * @param {object} [options] Optional settings.
  263. * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
  264. * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
  265. * @return {boolean}
  266. */
  267. MongoClient.prototype.isConnected = function(options) {
  268. options = options || {};
  269. if (!this.topology) return false;
  270. return this.topology.isConnected(options);
  271. };
  272. /**
  273. * Connect to MongoDB using a url as documented at
  274. *
  275. * docs.mongodb.org/manual/reference/connection-string/
  276. *
  277. * Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
  278. *
  279. * @method
  280. * @static
  281. * @param {string} url The connection URI string
  282. * @param {object} [options] Optional settings
  283. * @param {number} [options.poolSize=5] The maximum size of the individual server pool
  284. * @param {boolean} [options.ssl=false] Enable SSL connection. *deprecated* use `tls` variants
  285. * @param {boolean} [options.sslValidate=false] Validate mongod server certificate against Certificate Authority *deprecated* use `tls` variants
  286. * @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer *deprecated* use `tls` variants
  287. * @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer *deprecated* use `tls` variants
  288. * @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer *deprecated* use `tls` variants
  289. * @param {string} [options.sslPass=undefined] SSL Certificate pass phrase *deprecated* use `tls` variants
  290. * @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer *deprecated* use `tls` variants
  291. * @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. *deprecated* use `tls` variants
  292. * @param {boolean} [options.tls=false] Enable TLS connections
  293. * @param {boolean} [options.tlsinsecure=false] Relax TLS constraints, disabling validation
  294. * @param {string} [options.tlsCAFile] A path to file with either a single or bundle of certificate authorities to be considered trusted when making a TLS connection
  295. * @param {string} [options.tlsCertificateKeyFile] A path to the client certificate file or the client private key file; in the case that they both are needed, the files should be concatenated
  296. * @param {string} [options.tlsCertificateKeyFilePassword] The password to decrypt the client private key to be used for TLS connections
  297. * @param {boolean} [options.tlsAllowInvalidCertificates] Specifies whether or not the driver should error when the server’s TLS certificate is invalid
  298. * @param {boolean} [options.tlsAllowInvalidHostnames] Specifies whether or not the driver should error when there is a mismatch between the server’s hostname and the hostname specified by the TLS certificate
  299. * @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
  300. * @param {boolean} [options.noDelay=true] TCP Connection no delay
  301. * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
  302. * @param {boolean} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
  303. * @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
  304. * @param {number} [options.family] Version of IP stack. Can be 4, 6 or null (default).
  305. * If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
  306. * @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
  307. * @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
  308. * @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
  309. * @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
  310. * @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
  311. * @param {string} [options.replicaSet=undefined] The Replicaset set name
  312. * @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
  313. * @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
  314. * @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
  315. * @param {string} [options.authSource=undefined] Define the database to authenticate against
  316. * @param {(number|string)} [options.w] The write concern
  317. * @param {number} [options.wtimeout] The write concern timeout
  318. * @param {boolean} [options.j=false] Specify a journal write concern
  319. * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
  320. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
  321. * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
  322. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers
  323. * @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
  324. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
  325. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys
  326. * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
  327. * @param {object} [options.readConcern] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
  328. * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
  329. * @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
  330. * @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
  331. * @param {object} [options.logger=undefined] Custom logger object
  332. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
  333. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
  334. * @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
  335. * @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
  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;