db.js 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. 'use strict';
  2. const EventEmitter = require('events').EventEmitter;
  3. const inherits = require('util').inherits;
  4. const getSingleProperty = require('./utils').getSingleProperty;
  5. const CommandCursor = require('./command_cursor');
  6. const handleCallback = require('./utils').handleCallback;
  7. const filterOptions = require('./utils').filterOptions;
  8. const toError = require('./utils').toError;
  9. const ReadPreference = require('mongodb-core').ReadPreference;
  10. const MongoError = require('mongodb-core').MongoError;
  11. const ObjectID = require('mongodb-core').ObjectID;
  12. const Logger = require('mongodb-core').Logger;
  13. const Collection = require('./collection');
  14. const mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern;
  15. const executeOperation = require('./utils').executeOperation;
  16. const applyWriteConcern = require('./utils').applyWriteConcern;
  17. const resolveReadPreference = require('./utils').resolveReadPreference;
  18. const ChangeStream = require('./change_stream');
  19. const deprecate = require('util').deprecate;
  20. const deprecateOptions = require('./utils').deprecateOptions;
  21. const CONSTANTS = require('./constants');
  22. // Operations
  23. const addUser = require('./operations/db_ops').addUser;
  24. const aggregate = require('./operations/aggregate').aggregate;
  25. const collections = require('./operations/db_ops').collections;
  26. const createCollection = require('./operations/db_ops').createCollection;
  27. const createIndex = require('./operations/db_ops').createIndex;
  28. const createListener = require('./operations/db_ops').createListener;
  29. const dropCollection = require('./operations/db_ops').dropCollection;
  30. const dropDatabase = require('./operations/db_ops').dropDatabase;
  31. const ensureIndex = require('./operations/db_ops').ensureIndex;
  32. const evaluate = require('./operations/db_ops').evaluate;
  33. const executeCommand = require('./operations/db_ops').executeCommand;
  34. const executeDbAdminCommand = require('./operations/db_ops').executeDbAdminCommand;
  35. const indexInformation = require('./operations/db_ops').indexInformation;
  36. const listCollectionsTransforms = require('./operations/db_ops').listCollectionsTransforms;
  37. const profilingInfo = require('./operations/db_ops').profilingInfo;
  38. const profilingLevel = require('./operations/db_ops').profilingLevel;
  39. const removeUser = require('./operations/db_ops').removeUser;
  40. const setProfilingLevel = require('./operations/db_ops').setProfilingLevel;
  41. const validateDatabaseName = require('./operations/db_ops').validateDatabaseName;
  42. /**
  43. * @fileOverview The **Db** class is a class that represents a MongoDB Database.
  44. *
  45. * @example
  46. * const MongoClient = require('mongodb').MongoClient;
  47. * // Connection url
  48. * const url = 'mongodb://localhost:27017';
  49. * // Database Name
  50. * const dbName = 'test';
  51. * // Connect using MongoClient
  52. * MongoClient.connect(url, function(err, client) {
  53. * // Select the database by name
  54. * const testDb = client.db(dbName);
  55. * client.close();
  56. * });
  57. */
  58. // Allowed parameters
  59. const legalOptionNames = [
  60. 'w',
  61. 'wtimeout',
  62. 'fsync',
  63. 'j',
  64. 'readPreference',
  65. 'readPreferenceTags',
  66. 'native_parser',
  67. 'forceServerObjectId',
  68. 'pkFactory',
  69. 'serializeFunctions',
  70. 'raw',
  71. 'bufferMaxEntries',
  72. 'authSource',
  73. 'ignoreUndefined',
  74. 'promoteLongs',
  75. 'promiseLibrary',
  76. 'readConcern',
  77. 'retryMiliSeconds',
  78. 'numberOfRetries',
  79. 'parentDb',
  80. 'noListener',
  81. 'loggerLevel',
  82. 'logger',
  83. 'promoteBuffers',
  84. 'promoteLongs',
  85. 'promoteValues',
  86. 'compression',
  87. 'retryWrites'
  88. ];
  89. /**
  90. * Creates a new Db instance
  91. * @class
  92. * @param {string} databaseName The name of the database this instance represents.
  93. * @param {(Server|ReplSet|Mongos)} topology The server topology for the database.
  94. * @param {object} [options] Optional settings.
  95. * @param {string} [options.authSource] If the database authentication is dependent on another databaseName.
  96. * @param {(number|string)} [options.w] The write concern.
  97. * @param {number} [options.wtimeout] The write concern timeout.
  98. * @param {boolean} [options.j=false] Specify a journal write concern.
  99. * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
  100. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
  101. * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
  102. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  103. * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
  104. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
  105. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
  106. * @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.
  107. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  108. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
  109. * @param {object} [options.promiseLibrary] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
  110. * @param {object} [options.readConcern] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
  111. * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
  112. * @property {(Server|ReplSet|Mongos)} serverConfig Get the current db topology.
  113. * @property {number} bufferMaxEntries Current bufferMaxEntries value for the database
  114. * @property {string} databaseName The name of the database this instance represents.
  115. * @property {object} options The options associated with the db instance.
  116. * @property {boolean} native_parser The current value of the parameter native_parser.
  117. * @property {boolean} slaveOk The current slaveOk value for the db instance.
  118. * @property {object} writeConcern The current write concern values.
  119. * @property {object} topology Access the topology object (single server, replicaset or mongos).
  120. * @fires Db#close
  121. * @fires Db#reconnect
  122. * @fires Db#error
  123. * @fires Db#timeout
  124. * @fires Db#parseError
  125. * @fires Db#fullsetup
  126. * @return {Db} a Db instance.
  127. */
  128. function Db(databaseName, topology, options) {
  129. options = options || {};
  130. if (!(this instanceof Db)) return new Db(databaseName, topology, options);
  131. EventEmitter.call(this);
  132. // Get the promiseLibrary
  133. const promiseLibrary = options.promiseLibrary || Promise;
  134. // Filter the options
  135. options = filterOptions(options, legalOptionNames);
  136. // Ensure we put the promiseLib in the options
  137. options.promiseLibrary = promiseLibrary;
  138. // Internal state of the db object
  139. this.s = {
  140. // Database name
  141. databaseName: databaseName,
  142. // DbCache
  143. dbCache: {},
  144. // Children db's
  145. children: [],
  146. // Topology
  147. topology: topology,
  148. // Options
  149. options: options,
  150. // Logger instance
  151. logger: Logger('Db', options),
  152. // Get the bson parser
  153. bson: topology ? topology.bson : null,
  154. // Unpack read preference
  155. readPreference: options.readPreference,
  156. // Set buffermaxEntries
  157. bufferMaxEntries: typeof options.bufferMaxEntries === 'number' ? options.bufferMaxEntries : -1,
  158. // Parent db (if chained)
  159. parentDb: options.parentDb || null,
  160. // Set up the primary key factory or fallback to ObjectID
  161. pkFactory: options.pkFactory || ObjectID,
  162. // Get native parser
  163. nativeParser: options.nativeParser || options.native_parser,
  164. // Promise library
  165. promiseLibrary: promiseLibrary,
  166. // No listener
  167. noListener: typeof options.noListener === 'boolean' ? options.noListener : false,
  168. // ReadConcern
  169. readConcern: options.readConcern
  170. };
  171. // Ensure we have a valid db name
  172. validateDatabaseName(this.s.databaseName);
  173. // Add a read Only property
  174. getSingleProperty(this, 'serverConfig', this.s.topology);
  175. getSingleProperty(this, 'bufferMaxEntries', this.s.bufferMaxEntries);
  176. getSingleProperty(this, 'databaseName', this.s.databaseName);
  177. // This is a child db, do not register any listeners
  178. if (options.parentDb) return;
  179. if (this.s.noListener) return;
  180. // Add listeners
  181. topology.on('error', createListener(this, 'error', this));
  182. topology.on('timeout', createListener(this, 'timeout', this));
  183. topology.on('close', createListener(this, 'close', this));
  184. topology.on('parseError', createListener(this, 'parseError', this));
  185. topology.once('open', createListener(this, 'open', this));
  186. topology.once('fullsetup', createListener(this, 'fullsetup', this));
  187. topology.once('all', createListener(this, 'all', this));
  188. topology.on('reconnect', createListener(this, 'reconnect', this));
  189. }
  190. inherits(Db, EventEmitter);
  191. // Topology
  192. Object.defineProperty(Db.prototype, 'topology', {
  193. enumerable: true,
  194. get: function() {
  195. return this.s.topology;
  196. }
  197. });
  198. // Options
  199. Object.defineProperty(Db.prototype, 'options', {
  200. enumerable: true,
  201. get: function() {
  202. return this.s.options;
  203. }
  204. });
  205. // slaveOk specified
  206. Object.defineProperty(Db.prototype, 'slaveOk', {
  207. enumerable: true,
  208. get: function() {
  209. if (
  210. this.s.options.readPreference != null &&
  211. (this.s.options.readPreference !== 'primary' ||
  212. this.s.options.readPreference.mode !== 'primary')
  213. ) {
  214. return true;
  215. }
  216. return false;
  217. }
  218. });
  219. // get the write Concern
  220. Object.defineProperty(Db.prototype, 'writeConcern', {
  221. enumerable: true,
  222. get: function() {
  223. const ops = {};
  224. if (this.s.options.w != null) ops.w = this.s.options.w;
  225. if (this.s.options.j != null) ops.j = this.s.options.j;
  226. if (this.s.options.fsync != null) ops.fsync = this.s.options.fsync;
  227. if (this.s.options.wtimeout != null) ops.wtimeout = this.s.options.wtimeout;
  228. return ops;
  229. }
  230. });
  231. /**
  232. * Execute a command
  233. * @method
  234. * @param {object} command The command hash
  235. * @param {object} [options] Optional settings.
  236. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  237. * @param {ClientSession} [options.session] optional session to use for this operation
  238. * @param {Db~resultCallback} [callback] The command result callback
  239. * @return {Promise} returns Promise if no callback passed
  240. */
  241. Db.prototype.command = function(command, options, callback) {
  242. if (typeof options === 'function') (callback = options), (options = {});
  243. options = Object.assign({}, options);
  244. return executeOperation(this.s.topology, executeCommand, [this, command, options, callback]);
  245. };
  246. /**
  247. * Execute an aggregation framework pipeline against the database, needs MongoDB >= 3.6
  248. * @method
  249. * @param {object} [pipeline=[]] Array containing all the aggregation framework commands for the execution.
  250. * @param {object} [options] Optional settings.
  251. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  252. * @param {object} [options.cursor] Return the query as cursor, on 2.6 > it returns as a real cursor on pre 2.6 it returns as an emulated cursor.
  253. * @param {number} [options.cursor.batchSize] The batchSize for the cursor
  254. * @param {boolean} [options.explain=false] Explain returns the aggregation execution plan (requires mongodb 2.6 >).
  255. * @param {boolean} [options.allowDiskUse=false] allowDiskUse lets the server know if it can use disk to store temporary results for the aggregation (requires mongodb 2.6 >).
  256. * @param {number} [options.maxTimeMS] maxTimeMS specifies a cumulative time limit in milliseconds for processing operations on the cursor. MongoDB interrupts the operation at the earliest following interrupt point.
  257. * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
  258. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  259. * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
  260. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
  261. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
  262. * @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
  263. * @param {string} [options.comment] Add a comment to an aggregation command
  264. * @param {string|object} [options.hint] Add an index selection hint to an aggregation command
  265. * @param {ClientSession} [options.session] optional session to use for this operation
  266. * @param {Database~aggregationCallback} callback The command result callback
  267. * @return {(null|AggregationCursor)}
  268. */
  269. Db.prototype.aggregate = function(pipeline, options, callback) {
  270. if (typeof options === 'function') {
  271. callback = options;
  272. options = {};
  273. }
  274. // If we have no options or callback we are doing
  275. // a cursor based aggregation
  276. if (options == null && callback == null) {
  277. options = {};
  278. }
  279. return aggregate(this, '1', pipeline, options, callback);
  280. };
  281. /**
  282. * Return the Admin db instance
  283. * @method
  284. * @return {Admin} return the new Admin db instance
  285. */
  286. Db.prototype.admin = function() {
  287. const Admin = require('./admin');
  288. return new Admin(this, this.s.topology, this.s.promiseLibrary);
  289. };
  290. /**
  291. * The callback format for the collection method, must be used if strict is specified
  292. * @callback Db~collectionResultCallback
  293. * @param {MongoError} error An error instance representing the error during the execution.
  294. * @param {Collection} collection The collection instance.
  295. */
  296. /**
  297. * The callback format for an aggregation call
  298. * @callback Database~aggregationCallback
  299. * @param {MongoError} error An error instance representing the error during the execution.
  300. * @param {AggregationCursor} cursor The cursor if the aggregation command was executed successfully.
  301. */
  302. const collectionKeys = [
  303. 'pkFactory',
  304. 'readPreference',
  305. 'serializeFunctions',
  306. 'strict',
  307. 'readConcern',
  308. 'ignoreUndefined',
  309. 'promoteValues',
  310. 'promoteBuffers',
  311. 'promoteLongs'
  312. ];
  313. /**
  314. * Fetch a specific collection (containing the actual collection information). If the application does not use strict mode you
  315. * can use it without a callback in the following way: `const collection = db.collection('mycollection');`
  316. *
  317. * @method
  318. * @param {string} name the collection name we wish to access.
  319. * @param {object} [options] Optional settings.
  320. * @param {(number|string)} [options.w] The write concern.
  321. * @param {number} [options.wtimeout] The write concern timeout.
  322. * @param {boolean} [options.j=false] Specify a journal write concern.
  323. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  324. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
  325. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  326. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
  327. * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
  328. * @param {object} [options.readConcern] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
  329. * @param {ReadConcernLevel} [options.readConcern.level='local'] Specify a read concern level for the collection operations (only MongoDB 3.2 or higher supported)
  330. * @param {Db~collectionResultCallback} [callback] The collection result callback
  331. * @return {Collection} return the new Collection instance if not in strict mode
  332. */
  333. Db.prototype.collection = function(name, options, callback) {
  334. if (typeof options === 'function') (callback = options), (options = {});
  335. options = options || {};
  336. options = Object.assign({}, options);
  337. // Set the promise library
  338. options.promiseLibrary = this.s.promiseLibrary;
  339. // If we have not set a collection level readConcern set the db level one
  340. options.readConcern = options.readConcern || this.s.readConcern;
  341. // Do we have ignoreUndefined set
  342. if (this.s.options.ignoreUndefined) {
  343. options.ignoreUndefined = this.s.options.ignoreUndefined;
  344. }
  345. // Merge in all needed options and ensure correct writeConcern merging from db level
  346. options = mergeOptionsAndWriteConcern(options, this.s.options, collectionKeys, true);
  347. // Execute
  348. if (options == null || !options.strict) {
  349. try {
  350. const collection = new Collection(
  351. this,
  352. this.s.topology,
  353. this.s.databaseName,
  354. name,
  355. this.s.pkFactory,
  356. options
  357. );
  358. if (callback) callback(null, collection);
  359. return collection;
  360. } catch (err) {
  361. if (err instanceof MongoError && callback) return callback(err);
  362. throw err;
  363. }
  364. }
  365. // Strict mode
  366. if (typeof callback !== 'function') {
  367. throw toError(`A callback is required in strict mode. While getting collection ${name}`);
  368. }
  369. // Did the user destroy the topology
  370. if (this.serverConfig && this.serverConfig.isDestroyed()) {
  371. return callback(new MongoError('topology was destroyed'));
  372. }
  373. const listCollectionOptions = Object.assign({}, options, { nameOnly: true });
  374. // Strict mode
  375. this.listCollections({ name: name }, listCollectionOptions).toArray((err, collections) => {
  376. if (err != null) return handleCallback(callback, err, null);
  377. if (collections.length === 0)
  378. return handleCallback(
  379. callback,
  380. toError(`Collection ${name} does not exist. Currently in strict mode.`),
  381. null
  382. );
  383. try {
  384. return handleCallback(
  385. callback,
  386. null,
  387. new Collection(this, this.s.topology, this.s.databaseName, name, this.s.pkFactory, options)
  388. );
  389. } catch (err) {
  390. return handleCallback(callback, err, null);
  391. }
  392. });
  393. };
  394. /**
  395. * Create a new collection on a server with the specified options. Use this to create capped collections.
  396. * More information about command options available at https://docs.mongodb.com/manual/reference/command/create/
  397. *
  398. * @method
  399. * @param {string} name the collection name we wish to access.
  400. * @param {object} [options] Optional settings.
  401. * @param {(number|string)} [options.w] The write concern.
  402. * @param {number} [options.wtimeout] The write concern timeout.
  403. * @param {boolean} [options.j=false] Specify a journal write concern.
  404. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  405. * @param {object} [options.pkFactory] A primary key factory object for generation of custom _id keys.
  406. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  407. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
  408. * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
  409. * @param {boolean} [options.capped=false] Create a capped collection.
  410. * @param {boolean} [options.autoIndexId=true] DEPRECATED: Create an index on the _id field of the document, True by default on MongoDB 2.6 - 3.0
  411. * @param {number} [options.size] The size of the capped collection in bytes.
  412. * @param {number} [options.max] The maximum number of documents in the capped collection.
  413. * @param {number} [options.flags] Optional. Available for the MMAPv1 storage engine only to set the usePowerOf2Sizes and the noPadding flag.
  414. * @param {object} [options.storageEngine] Allows users to specify configuration to the storage engine on a per-collection basis when creating a collection on MongoDB 3.0 or higher.
  415. * @param {object} [options.validator] Allows users to specify validation rules or expressions for the collection. For more information, see Document Validation on MongoDB 3.2 or higher.
  416. * @param {string} [options.validationLevel] Determines how strictly MongoDB applies the validation rules to existing documents during an update on MongoDB 3.2 or higher.
  417. * @param {string} [options.validationAction] Determines whether to error on invalid documents or just warn about the violations but allow invalid documents to be inserted on MongoDB 3.2 or higher.
  418. * @param {object} [options.indexOptionDefaults] Allows users to specify a default configuration for indexes when creating a collection on MongoDB 3.2 or higher.
  419. * @param {string} [options.viewOn] The name of the source collection or view from which to create the view. The name is not the full namespace of the collection or view; i.e. does not include the database name and implies the same database as the view to create on MongoDB 3.4 or higher.
  420. * @param {array} [options.pipeline] An array that consists of the aggregation pipeline stage. create creates the view by applying the specified pipeline to the viewOn collection or view on MongoDB 3.4 or higher.
  421. * @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
  422. * @param {ClientSession} [options.session] optional session to use for this operation
  423. * @param {Db~collectionResultCallback} [callback] The results callback
  424. * @return {Promise} returns Promise if no callback passed
  425. */
  426. Db.prototype.createCollection = deprecateOptions(
  427. {
  428. name: 'Db.createCollection',
  429. deprecatedOptions: ['autoIndexId'],
  430. optionsIndex: 1
  431. },
  432. function(name, options, callback) {
  433. if (typeof options === 'function') (callback = options), (options = {});
  434. options = options || {};
  435. options.promiseLibrary = options.promiseLibrary || this.s.promiseLibrary;
  436. return executeOperation(this.s.topology, createCollection, [this, name, options, callback]);
  437. }
  438. );
  439. /**
  440. * Get all the db statistics.
  441. *
  442. * @method
  443. * @param {object} [options] Optional settings.
  444. * @param {number} [options.scale] Divide the returned sizes by scale value.
  445. * @param {ClientSession} [options.session] optional session to use for this operation
  446. * @param {Db~resultCallback} [callback] The collection result callback
  447. * @return {Promise} returns Promise if no callback passed
  448. */
  449. Db.prototype.stats = function(options, callback) {
  450. if (typeof options === 'function') (callback = options), (options = {});
  451. options = options || {};
  452. // Build command object
  453. const commandObject = { dbStats: true };
  454. // Check if we have the scale value
  455. if (options['scale'] != null) commandObject['scale'] = options['scale'];
  456. // If we have a readPreference set
  457. if (options.readPreference == null && this.s.readPreference) {
  458. options.readPreference = this.s.readPreference;
  459. }
  460. // Execute the command
  461. return this.command(commandObject, options, callback);
  462. };
  463. /**
  464. * Get the list of all collection information for the specified db.
  465. *
  466. * @method
  467. * @param {object} [filter={}] Query to filter collections by
  468. * @param {object} [options] Optional settings.
  469. * @param {boolean} [options.nameOnly=false] Since 4.0: If true, will only return the collection name in the response, and will omit additional info
  470. * @param {number} [options.batchSize] The batchSize for the returned command cursor or if pre 2.8 the systems batch collection
  471. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  472. * @param {ClientSession} [options.session] optional session to use for this operation
  473. * @return {CommandCursor}
  474. */
  475. Db.prototype.listCollections = function(filter, options) {
  476. filter = filter || {};
  477. options = options || {};
  478. // Shallow clone the object
  479. options = Object.assign({}, options);
  480. // Set the promise library
  481. options.promiseLibrary = this.s.promiseLibrary;
  482. // Ensure valid readPreference
  483. options.readPreference = resolveReadPreference(options, {
  484. db: this,
  485. default: ReadPreference.primary
  486. });
  487. // Cursor options
  488. let cursor = options.batchSize ? { batchSize: options.batchSize } : {};
  489. // We have a list collections command
  490. if (this.serverConfig.capabilities().hasListCollectionsCommand) {
  491. const nameOnly = typeof options.nameOnly === 'boolean' ? options.nameOnly : false;
  492. // Build the command
  493. const command = { listCollections: true, filter, cursor, nameOnly };
  494. // Set the AggregationCursor constructor
  495. options.cursorFactory = CommandCursor;
  496. // Create the cursor
  497. cursor = this.s.topology.cursor(`${this.s.databaseName}.$cmd`, command, options);
  498. // Do we have a readPreference, apply it
  499. if (options.readPreference) {
  500. cursor.setReadPreference(options.readPreference);
  501. }
  502. // Return the cursor
  503. return cursor;
  504. }
  505. // We cannot use the listCollectionsCommand
  506. if (!this.serverConfig.capabilities().hasListCollectionsCommand) {
  507. // If we have legacy mode and have not provided a full db name filter it
  508. if (
  509. typeof filter.name === 'string' &&
  510. !new RegExp('^' + this.databaseName + '\\.').test(filter.name)
  511. ) {
  512. filter = Object.assign({}, filter);
  513. filter.name = `${this.s.databaseName}.${filter.name}`;
  514. }
  515. }
  516. // No filter, filter by current database
  517. if (filter == null) {
  518. filter.name = `/${this.s.databaseName}/`;
  519. }
  520. // Rewrite the filter to use $and to filter out indexes
  521. if (filter.name) {
  522. filter = { $and: [{ name: filter.name }, { name: /^((?!\$).)*$/ }] };
  523. } else {
  524. filter = { name: /^((?!\$).)*$/ };
  525. }
  526. // Return options
  527. const _options = { transforms: listCollectionsTransforms(this.s.databaseName) };
  528. // Get the cursor
  529. cursor = this.collection(CONSTANTS.SYSTEM_NAMESPACE_COLLECTION).find(filter, _options);
  530. // Do we have a readPreference, apply it
  531. if (options.readPreference) cursor.setReadPreference(options.readPreference);
  532. // Set the passed in batch size if one was provided
  533. if (options.batchSize) cursor = cursor.batchSize(options.batchSize);
  534. // We have a fallback mode using legacy systems collections
  535. return cursor;
  536. };
  537. /**
  538. * Evaluate JavaScript on the server
  539. *
  540. * @method
  541. * @param {Code} code JavaScript to execute on server.
  542. * @param {(object|array)} parameters The parameters for the call.
  543. * @param {object} [options] Optional settings.
  544. * @param {boolean} [options.nolock=false] Tell MongoDB not to block on the evaluation of the javascript.
  545. * @param {ClientSession} [options.session] optional session to use for this operation
  546. * @param {Db~resultCallback} [callback] The results callback
  547. * @deprecated Eval is deprecated on MongoDB 3.2 and forward
  548. * @return {Promise} returns Promise if no callback passed
  549. */
  550. Db.prototype.eval = deprecate(function(code, parameters, options, callback) {
  551. const args = Array.prototype.slice.call(arguments, 1);
  552. callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
  553. parameters = args.length ? args.shift() : parameters;
  554. options = args.length ? args.shift() || {} : {};
  555. return executeOperation(this.s.topology, evaluate, [this, code, parameters, options, callback]);
  556. }, 'Db.eval is deprecated as of MongoDB version 3.2');
  557. /**
  558. * Rename a collection.
  559. *
  560. * @method
  561. * @param {string} fromCollection Name of current collection to rename.
  562. * @param {string} toCollection New name of of the collection.
  563. * @param {object} [options] Optional settings.
  564. * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
  565. * @param {ClientSession} [options.session] optional session to use for this operation
  566. * @param {Db~collectionResultCallback} [callback] The results callback
  567. * @return {Promise} returns Promise if no callback passed
  568. */
  569. Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) {
  570. if (typeof options === 'function') (callback = options), (options = {});
  571. options = options || {};
  572. // Add return new collection
  573. options.new_collection = true;
  574. const collection = this.collection(fromCollection);
  575. return executeOperation(this.s.topology, collection.rename.bind(collection), [
  576. toCollection,
  577. options,
  578. callback
  579. ]);
  580. };
  581. /**
  582. * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
  583. *
  584. * @method
  585. * @param {string} name Name of collection to drop
  586. * @param {Object} [options] Optional settings
  587. * @param {ClientSession} [options.session] optional session to use for this operation
  588. * @param {Db~resultCallback} [callback] The results callback
  589. * @return {Promise} returns Promise if no callback passed
  590. */
  591. Db.prototype.dropCollection = function(name, options, callback) {
  592. if (typeof options === 'function') (callback = options), (options = {});
  593. options = options || {};
  594. // Command to execute
  595. const cmd = { drop: name };
  596. // Decorate with write concern
  597. applyWriteConcern(cmd, { db: this }, options);
  598. // options
  599. const opts = Object.assign({}, this.s.options, { readPreference: ReadPreference.PRIMARY });
  600. if (options.session) opts.session = options.session;
  601. return executeOperation(this.s.topology, dropCollection, [this, cmd, opts, callback]);
  602. };
  603. /**
  604. * Drop a database, removing it permanently from the server.
  605. *
  606. * @method
  607. * @param {Object} [options] Optional settings
  608. * @param {ClientSession} [options.session] optional session to use for this operation
  609. * @param {Db~resultCallback} [callback] The results callback
  610. * @return {Promise} returns Promise if no callback passed
  611. */
  612. Db.prototype.dropDatabase = function(options, callback) {
  613. if (typeof options === 'function') (callback = options), (options = {});
  614. options = options || {};
  615. // Drop database command
  616. const cmd = { dropDatabase: 1 };
  617. // Decorate with write concern
  618. applyWriteConcern(cmd, { db: this }, options);
  619. // Ensure primary only
  620. const finalOptions = Object.assign({}, this.s.options, {
  621. readPreference: ReadPreference.PRIMARY
  622. });
  623. if (options.session) {
  624. finalOptions.session = options.session;
  625. }
  626. return executeOperation(this.s.topology, dropDatabase, [this, cmd, finalOptions, callback]);
  627. };
  628. /**
  629. * Fetch all collections for the current db.
  630. *
  631. * @method
  632. * @param {Object} [options] Optional settings
  633. * @param {ClientSession} [options.session] optional session to use for this operation
  634. * @param {Db~collectionsResultCallback} [callback] The results callback
  635. * @return {Promise} returns Promise if no callback passed
  636. */
  637. Db.prototype.collections = function(options, callback) {
  638. if (typeof options === 'function') (callback = options), (options = {});
  639. options = options || {};
  640. return executeOperation(this.s.topology, collections, [this, options, callback]);
  641. };
  642. /**
  643. * Runs a command on the database as admin.
  644. * @method
  645. * @param {object} command The command hash
  646. * @param {object} [options] Optional settings.
  647. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  648. * @param {ClientSession} [options.session] optional session to use for this operation
  649. * @param {Db~resultCallback} [callback] The command result callback
  650. * @return {Promise} returns Promise if no callback passed
  651. */
  652. Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
  653. if (typeof options === 'function') (callback = options), (options = {});
  654. options = options || {};
  655. options.readPreference = resolveReadPreference(options);
  656. return executeOperation(this.s.topology, executeDbAdminCommand, [
  657. this,
  658. selector,
  659. options,
  660. callback
  661. ]);
  662. };
  663. /**
  664. * Creates an index on the db and collection.
  665. * @method
  666. * @param {string} name Name of the collection to create the index on.
  667. * @param {(string|object)} fieldOrSpec Defines the index.
  668. * @param {object} [options] Optional settings.
  669. * @param {(number|string)} [options.w] The write concern.
  670. * @param {number} [options.wtimeout] The write concern timeout.
  671. * @param {boolean} [options.j=false] Specify a journal write concern.
  672. * @param {boolean} [options.unique=false] Creates an unique index.
  673. * @param {boolean} [options.sparse=false] Creates a sparse index.
  674. * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
  675. * @param {boolean} [options.dropDups=false] A unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
  676. * @param {number} [options.min] For geospatial indexes set the lower bound for the co-ordinates.
  677. * @param {number} [options.max] For geospatial indexes set the high bound for the co-ordinates.
  678. * @param {number} [options.v] Specify the format version of the indexes.
  679. * @param {number} [options.expireAfterSeconds] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
  680. * @param {number} [options.name] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
  681. * @param {object} [options.partialFilterExpression] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
  682. * @param {ClientSession} [options.session] optional session to use for this operation
  683. * @param {Db~resultCallback} [callback] The command result callback
  684. * @return {Promise} returns Promise if no callback passed
  685. */
  686. Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
  687. if (typeof options === 'function') (callback = options), (options = {});
  688. options = options ? Object.assign({}, options) : {};
  689. return executeOperation(this.s.topology, createIndex, [
  690. this,
  691. name,
  692. fieldOrSpec,
  693. options,
  694. callback
  695. ]);
  696. };
  697. /**
  698. * Ensures that an index exists, if it does not it creates it
  699. * @method
  700. * @deprecated since version 2.0
  701. * @param {string} name The index name
  702. * @param {(string|object)} fieldOrSpec Defines the index.
  703. * @param {object} [options] Optional settings.
  704. * @param {(number|string)} [options.w] The write concern.
  705. * @param {number} [options.wtimeout] The write concern timeout.
  706. * @param {boolean} [options.j=false] Specify a journal write concern.
  707. * @param {boolean} [options.unique=false] Creates an unique index.
  708. * @param {boolean} [options.sparse=false] Creates a sparse index.
  709. * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
  710. * @param {boolean} [options.dropDups=false] A unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
  711. * @param {number} [options.min] For geospatial indexes set the lower bound for the co-ordinates.
  712. * @param {number} [options.max] For geospatial indexes set the high bound for the co-ordinates.
  713. * @param {number} [options.v] Specify the format version of the indexes.
  714. * @param {number} [options.expireAfterSeconds] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
  715. * @param {number} [options.name] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
  716. * @param {ClientSession} [options.session] optional session to use for this operation
  717. * @param {Db~resultCallback} [callback] The command result callback
  718. * @return {Promise} returns Promise if no callback passed
  719. */
  720. Db.prototype.ensureIndex = deprecate(function(name, fieldOrSpec, options, callback) {
  721. if (typeof options === 'function') (callback = options), (options = {});
  722. options = options || {};
  723. return executeOperation(this.s.topology, ensureIndex, [
  724. this,
  725. name,
  726. fieldOrSpec,
  727. options,
  728. callback
  729. ]);
  730. }, 'Db.ensureIndex is deprecated as of MongoDB version 3.0 / driver version 2.0');
  731. Db.prototype.addChild = function(db) {
  732. if (this.s.parentDb) return this.s.parentDb.addChild(db);
  733. this.s.children.push(db);
  734. };
  735. /**
  736. * Add a user to the database.
  737. * @method
  738. * @param {string} username The username.
  739. * @param {string} password The password.
  740. * @param {object} [options] Optional settings.
  741. * @param {(number|string)} [options.w] The write concern.
  742. * @param {number} [options.wtimeout] The write concern timeout.
  743. * @param {boolean} [options.j=false] Specify a journal write concern.
  744. * @param {object} [options.customData] Custom data associated with the user (only Mongodb 2.6 or higher)
  745. * @param {object[]} [options.roles] Roles associated with the created user (only Mongodb 2.6 or higher)
  746. * @param {ClientSession} [options.session] optional session to use for this operation
  747. * @param {Db~resultCallback} [callback] The command result callback
  748. * @return {Promise} returns Promise if no callback passed
  749. */
  750. Db.prototype.addUser = function(username, password, options, callback) {
  751. if (typeof options === 'function') (callback = options), (options = {});
  752. options = options || {};
  753. return executeOperation(this.s.topology, addUser, [this, username, password, options, callback]);
  754. };
  755. /**
  756. * Remove a user from a database
  757. * @method
  758. * @param {string} username The username.
  759. * @param {object} [options] Optional settings.
  760. * @param {(number|string)} [options.w] The write concern.
  761. * @param {number} [options.wtimeout] The write concern timeout.
  762. * @param {boolean} [options.j=false] Specify a journal write concern.
  763. * @param {ClientSession} [options.session] optional session to use for this operation
  764. * @param {Db~resultCallback} [callback] The command result callback
  765. * @return {Promise} returns Promise if no callback passed
  766. */
  767. Db.prototype.removeUser = function(username, options, callback) {
  768. if (typeof options === 'function') (callback = options), (options = {});
  769. options = options || {};
  770. return executeOperation(this.s.topology, removeUser, [this, username, options, callback]);
  771. };
  772. /**
  773. * Set the current profiling level of MongoDB
  774. *
  775. * @param {string} level The new profiling level (off, slow_only, all).
  776. * @param {Object} [options] Optional settings
  777. * @param {ClientSession} [options.session] optional session to use for this operation
  778. * @param {Db~resultCallback} [callback] The command result callback.
  779. * @return {Promise} returns Promise if no callback passed
  780. */
  781. Db.prototype.setProfilingLevel = function(level, options, callback) {
  782. if (typeof options === 'function') (callback = options), (options = {});
  783. options = options || {};
  784. return executeOperation(this.s.topology, setProfilingLevel, [this, level, options, callback]);
  785. };
  786. /**
  787. * Retrieve the current profiling information for MongoDB
  788. *
  789. * @param {Object} [options] Optional settings
  790. * @param {ClientSession} [options.session] optional session to use for this operation
  791. * @param {Db~resultCallback} [callback] The command result callback.
  792. * @return {Promise} returns Promise if no callback passed
  793. * @deprecated Query the system.profile collection directly.
  794. */
  795. Db.prototype.profilingInfo = deprecate(function(options, callback) {
  796. if (typeof options === 'function') (callback = options), (options = {});
  797. options = options || {};
  798. return executeOperation(this.s.topology, profilingInfo, [this, options, callback]);
  799. }, 'Db.profilingInfo is deprecated. Query the system.profile collection directly.');
  800. /**
  801. * Retrieve the current profiling Level for MongoDB
  802. *
  803. * @param {Object} [options] Optional settings
  804. * @param {ClientSession} [options.session] optional session to use for this operation
  805. * @param {Db~resultCallback} [callback] The command result callback
  806. * @return {Promise} returns Promise if no callback passed
  807. */
  808. Db.prototype.profilingLevel = function(options, callback) {
  809. if (typeof options === 'function') (callback = options), (options = {});
  810. options = options || {};
  811. return executeOperation(this.s.topology, profilingLevel, [this, options, callback]);
  812. };
  813. /**
  814. * Retrieves this collections index info.
  815. * @method
  816. * @param {string} name The name of the collection.
  817. * @param {object} [options] Optional settings.
  818. * @param {boolean} [options.full=false] Returns the full raw index information.
  819. * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  820. * @param {ClientSession} [options.session] optional session to use for this operation
  821. * @param {Db~resultCallback} [callback] The command result callback
  822. * @return {Promise} returns Promise if no callback passed
  823. */
  824. Db.prototype.indexInformation = function(name, options, callback) {
  825. if (typeof options === 'function') (callback = options), (options = {});
  826. options = options || {};
  827. return executeOperation(this.s.topology, indexInformation, [this, name, options, callback]);
  828. };
  829. /**
  830. * Unref all sockets
  831. * @method
  832. */
  833. Db.prototype.unref = function() {
  834. this.s.topology.unref();
  835. };
  836. /**
  837. * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this database. Will ignore all changes to system collections.
  838. * @method
  839. * @since 3.1.0
  840. * @param {Array} [pipeline] An array of {@link https://docs.mongodb.com/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.
  841. * @param {object} [options] Optional settings
  842. * @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.
  843. * @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.
  844. * @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
  845. * @param {number} [options.batchSize] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
  846. * @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
  847. * @param {ReadPreference} [options.readPreference] The read preference. Defaults to the read preference of the database. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
  848. * @param {Timestamp} [options.startAtClusterTime] receive change events that occur after the specified timestamp
  849. * @param {ClientSession} [options.session] optional session to use for this operation
  850. * @return {ChangeStream} a ChangeStream instance.
  851. */
  852. Db.prototype.watch = function(pipeline, options) {
  853. pipeline = pipeline || [];
  854. options = options || {};
  855. // Allow optionally not specifying a pipeline
  856. if (!Array.isArray(pipeline)) {
  857. options = pipeline;
  858. pipeline = [];
  859. }
  860. return new ChangeStream(this, pipeline, options);
  861. };
  862. /**
  863. * Return the db logger
  864. * @method
  865. * @return {Logger} return the db logger
  866. * @ignore
  867. */
  868. Db.prototype.getLogger = function() {
  869. return this.s.logger;
  870. };
  871. /**
  872. * Db close event
  873. *
  874. * Emitted after a socket closed against a single server or mongos proxy.
  875. *
  876. * @event Db#close
  877. * @type {MongoError}
  878. */
  879. /**
  880. * Db reconnect event
  881. *
  882. * * Server: Emitted when the driver has reconnected and re-authenticated.
  883. * * ReplicaSet: N/A
  884. * * Mongos: Emitted when the driver reconnects and re-authenticates successfully against a Mongos.
  885. *
  886. * @event Db#reconnect
  887. * @type {object}
  888. */
  889. /**
  890. * Db error event
  891. *
  892. * Emitted after an error occurred against a single server or mongos proxy.
  893. *
  894. * @event Db#error
  895. * @type {MongoError}
  896. */
  897. /**
  898. * Db timeout event
  899. *
  900. * Emitted after a socket timeout occurred against a single server or mongos proxy.
  901. *
  902. * @event Db#timeout
  903. * @type {MongoError}
  904. */
  905. /**
  906. * Db parseError event
  907. *
  908. * The parseError event is emitted if the driver detects illegal or corrupt BSON being received from the server.
  909. *
  910. * @event Db#parseError
  911. * @type {MongoError}
  912. */
  913. /**
  914. * Db fullsetup event, emitted when all servers in the topology have been connected to at start up time.
  915. *
  916. * * Server: Emitted when the driver has connected to the single server and has authenticated.
  917. * * ReplSet: Emitted after the driver has attempted to connect to all replicaset members.
  918. * * Mongos: Emitted after the driver has attempted to connect to all mongos proxies.
  919. *
  920. * @event Db#fullsetup
  921. * @type {Db}
  922. */
  923. // Constants
  924. Db.SYSTEM_NAMESPACE_COLLECTION = CONSTANTS.SYSTEM_NAMESPACE_COLLECTION;
  925. Db.SYSTEM_INDEX_COLLECTION = CONSTANTS.SYSTEM_INDEX_COLLECTION;
  926. Db.SYSTEM_PROFILE_COLLECTION = CONSTANTS.SYSTEM_PROFILE_COLLECTION;
  927. Db.SYSTEM_USER_COLLECTION = CONSTANTS.SYSTEM_USER_COLLECTION;
  928. Db.SYSTEM_COMMAND_COLLECTION = CONSTANTS.SYSTEM_COMMAND_COLLECTION;
  929. Db.SYSTEM_JS_COLLECTION = CONSTANTS.SYSTEM_JS_COLLECTION;
  930. module.exports = Db;