db.js 42 KB

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