Source: lib/db.js

  1. "use strict";
  2. var EventEmitter = require('events').EventEmitter
  3. , authenticate = require('./authenticate')
  4. , inherits = require('util').inherits
  5. , getSingleProperty = require('./utils').getSingleProperty
  6. , shallowClone = require('./utils').shallowClone
  7. , parseIndexOptions = require('./utils').parseIndexOptions
  8. , debugOptions = require('./utils').debugOptions
  9. , CommandCursor = require('./command_cursor')
  10. , handleCallback = require('./utils').handleCallback
  11. , filterOptions = require('./utils').filterOptions
  12. , toError = require('./utils').toError
  13. , ReadPreference = require('./read_preference')
  14. , f = require('util').format
  15. , Admin = require('./admin')
  16. , Code = require('mongodb-core').BSON.Code
  17. , CoreReadPreference = require('mongodb-core').ReadPreference
  18. , MongoError = require('mongodb-core').MongoError
  19. , ObjectID = require('mongodb-core').ObjectID
  20. , Define = require('./metadata')
  21. , Logger = require('mongodb-core').Logger
  22. , Collection = require('./collection')
  23. , crypto = require('crypto')
  24. , mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern
  25. , assign = require('./utils').assign;
  26. var debugFields = ['authSource', 'w', 'wtimeout', 'j', 'native_parser', 'forceServerObjectId'
  27. , 'serializeFunctions', 'raw', 'promoteLongs', 'promoteValues', 'promoteBuffers', 'bufferMaxEntries', 'numberOfRetries', 'retryMiliSeconds'
  28. , 'readPreference', 'pkFactory', 'parentDb', 'promiseLibrary', 'noListener'];
  29. // Filter out any write concern options
  30. var illegalCommandFields = ['w', 'wtimeout', 'j', 'fsync', 'autoIndexId'
  31. , 'strict', 'serializeFunctions', 'pkFactory', 'raw', 'readPreference'];
  32. /**
  33. * @fileOverview The **Db** class is a class that represents a MongoDB Database.
  34. *
  35. * @example
  36. * var MongoClient = require('mongodb').MongoClient,
  37. * test = require('assert');
  38. * // Connection url
  39. * var url = 'mongodb://localhost:27017/test';
  40. * // Connect using MongoClient
  41. * MongoClient.connect(url, function(err, db) {
  42. * // Get an additional db
  43. * var testDb = db.db('test');
  44. * db.close();
  45. * });
  46. */
  47. // Allowed parameters
  48. var legalOptionNames = ['w', 'wtimeout', 'fsync', 'j', 'readPreference', 'readPreferenceTags', 'native_parser'
  49. , 'forceServerObjectId', 'pkFactory', 'serializeFunctions', 'raw', 'bufferMaxEntries', 'authSource'
  50. , 'ignoreUndefined', 'promoteLongs', 'promiseLibrary', 'readConcern', 'retryMiliSeconds', 'numberOfRetries'
  51. , 'parentDb', 'noListener', 'loggerLevel', 'logger', 'promoteBuffers', 'promoteLongs', 'promoteValues'];
  52. /**
  53. * Creates a new Db instance
  54. * @class
  55. * @param {string} databaseName The name of the database this instance represents.
  56. * @param {(Server|ReplSet|Mongos)} topology The server topology for the database.
  57. * @param {object} [options=null] Optional settings.
  58. * @param {string} [options.authSource=null] If the database authentication is dependent on another databaseName.
  59. * @param {(number|string)} [options.w=null] The write concern.
  60. * @param {number} [options.wtimeout=null] The write concern timeout.
  61. * @param {boolean} [options.j=false] Specify a journal write concern.
  62. * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
  63. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
  64. * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
  65. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  66. * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
  67. * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
  68. * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
  69. * @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.
  70. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  71. * @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
  72. * @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
  73. * @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
  74. * @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)
  75. * @property {(Server|ReplSet|Mongos)} serverConfig Get the current db topology.
  76. * @property {number} bufferMaxEntries Current bufferMaxEntries value for the database
  77. * @property {string} databaseName The name of the database this instance represents.
  78. * @property {object} options The options associated with the db instance.
  79. * @property {boolean} native_parser The current value of the parameter native_parser.
  80. * @property {boolean} slaveOk The current slaveOk value for the db instance.
  81. * @property {object} writeConcern The current write concern values.
  82. * @property {object} topology Access the topology object (single server, replicaset or mongos).
  83. * @fires Db#close
  84. * @fires Db#authenticated
  85. * @fires Db#reconnect
  86. * @fires Db#error
  87. * @fires Db#timeout
  88. * @fires Db#parseError
  89. * @fires Db#fullsetup
  90. * @return {Db} a Db instance.
  91. */
  92. var Db = function(databaseName, topology, options) {
  93. options = options || {};
  94. if(!(this instanceof Db)) return new Db(databaseName, topology, options);
  95. EventEmitter.call(this);
  96. var self = this;
  97. // Get the promiseLibrary
  98. var promiseLibrary = options.promiseLibrary;
  99. // No promise library selected fall back
  100. if(!promiseLibrary) {
  101. promiseLibrary = typeof global.Promise == 'function' ?
  102. global.Promise : require('es6-promise').Promise;
  103. }
  104. // Filter the options
  105. options = filterOptions(options, legalOptionNames);
  106. // Ensure we put the promiseLib in the options
  107. options.promiseLibrary = promiseLibrary;
  108. // var self = this; // Internal state of the db object
  109. this.s = {
  110. // Database name
  111. databaseName: databaseName
  112. // DbCache
  113. , dbCache: {}
  114. // Children db's
  115. , children: []
  116. // Topology
  117. , topology: topology
  118. // Options
  119. , options: options
  120. // Logger instance
  121. , logger: Logger('Db', options)
  122. // Get the bson parser
  123. , bson: topology ? topology.bson : null
  124. // Authsource if any
  125. , authSource: options.authSource
  126. // Unpack read preference
  127. , readPreference: options.readPreference
  128. // Set buffermaxEntries
  129. , bufferMaxEntries: typeof options.bufferMaxEntries == 'number' ? options.bufferMaxEntries : -1
  130. // Parent db (if chained)
  131. , parentDb: options.parentDb || null
  132. // Set up the primary key factory or fallback to ObjectID
  133. , pkFactory: options.pkFactory || ObjectID
  134. // Get native parser
  135. , nativeParser: options.nativeParser || options.native_parser
  136. // Promise library
  137. , promiseLibrary: promiseLibrary
  138. // No listener
  139. , noListener: typeof options.noListener == 'boolean' ? options.noListener : false
  140. // ReadConcern
  141. , readConcern: options.readConcern
  142. }
  143. // Ensure we have a valid db name
  144. validateDatabaseName(self.s.databaseName);
  145. // Add a read Only property
  146. getSingleProperty(this, 'serverConfig', self.s.topology);
  147. getSingleProperty(this, 'bufferMaxEntries', self.s.bufferMaxEntries);
  148. getSingleProperty(this, 'databaseName', self.s.databaseName);
  149. // This is a child db, do not register any listeners
  150. if(options.parentDb) return;
  151. if(this.s.noListener) return;
  152. // Add listeners
  153. topology.on('error', createListener(self, 'error', self));
  154. topology.on('timeout', createListener(self, 'timeout', self));
  155. topology.on('close', createListener(self, 'close', self));
  156. topology.on('parseError', createListener(self, 'parseError', self));
  157. topology.once('open', createListener(self, 'open', self));
  158. topology.once('fullsetup', createListener(self, 'fullsetup', self));
  159. topology.once('all', createListener(self, 'all', self));
  160. topology.on('reconnect', createListener(self, 'reconnect', self));
  161. topology.on('reconnectFailed', createListener(self, 'reconnectFailed', self));
  162. }
  163. inherits(Db, EventEmitter);
  164. var define = Db.define = new Define('Db', Db, false);
  165. // Topology
  166. Object.defineProperty(Db.prototype, 'topology', {
  167. enumerable:true,
  168. get: function() { return this.s.topology; }
  169. });
  170. // Options
  171. Object.defineProperty(Db.prototype, 'options', {
  172. enumerable:true,
  173. get: function() { return this.s.options; }
  174. });
  175. // slaveOk specified
  176. Object.defineProperty(Db.prototype, 'slaveOk', {
  177. enumerable:true,
  178. get: function() {
  179. if(this.s.options.readPreference != null
  180. && (this.s.options.readPreference != 'primary' || this.s.options.readPreference.mode != 'primary')) {
  181. return true;
  182. }
  183. return false;
  184. }
  185. });
  186. // get the write Concern
  187. Object.defineProperty(Db.prototype, 'writeConcern', {
  188. enumerable:true,
  189. get: function() {
  190. var ops = {};
  191. if(this.s.options.w != null) ops.w = this.s.options.w;
  192. if(this.s.options.j != null) ops.j = this.s.options.j;
  193. if(this.s.options.fsync != null) ops.fsync = this.s.options.fsync;
  194. if(this.s.options.wtimeout != null) ops.wtimeout = this.s.options.wtimeout;
  195. return ops;
  196. }
  197. });
  198. /**
  199. * The callback format for the Db.open method
  200. * @callback Db~openCallback
  201. * @param {MongoError} error An error instance representing the error during the execution.
  202. * @param {Db} db The Db instance if the open method was successful.
  203. */
  204. // Internal method
  205. var open = function(self, callback) {
  206. self.s.topology.connect(self, self.s.options, function(err) {
  207. if(callback == null) return;
  208. var internalCallback = callback;
  209. callback == null;
  210. if(err) {
  211. self.close();
  212. return internalCallback(err);
  213. }
  214. internalCallback(null, self);
  215. });
  216. }
  217. /**
  218. * Open the database
  219. * @method
  220. * @param {Db~openCallback} [callback] Callback
  221. * @return {Promise} returns Promise if no callback passed
  222. */
  223. Db.prototype.open = function(callback) {
  224. var self = this;
  225. // We provided a callback leg
  226. if(typeof callback == 'function') return open(self, callback);
  227. // Return promise
  228. return new self.s.promiseLibrary(function(resolve, reject) {
  229. open(self, function(err, db) {
  230. if(err) return reject(err);
  231. resolve(db);
  232. })
  233. });
  234. }
  235. define.classMethod('open', {callback: true, promise:true});
  236. /**
  237. * Converts provided read preference to CoreReadPreference
  238. * @param {(ReadPreference|string|object)} readPreference the user provided read preference
  239. * @return {CoreReadPreference}
  240. */
  241. var convertReadPreference = function(readPreference) {
  242. if(readPreference && typeof readPreference == 'string') {
  243. return new CoreReadPreference(readPreference);
  244. } else if(readPreference instanceof ReadPreference) {
  245. return new CoreReadPreference(readPreference.mode, readPreference.tags, {maxStalenessSeconds: readPreference.maxStalenessSeconds});
  246. } else if(readPreference && typeof readPreference == 'object') {
  247. var mode = readPreference.mode || readPreference.preference;
  248. if (mode && typeof mode == 'string') {
  249. readPreference = new CoreReadPreference(mode, readPreference.tags, {maxStalenessSeconds: readPreference.maxStalenessSeconds});
  250. }
  251. }
  252. return readPreference;
  253. }
  254. /**
  255. * The callback format for results
  256. * @callback Db~resultCallback
  257. * @param {MongoError} error An error instance representing the error during the execution.
  258. * @param {object} result The result object if the command was executed successfully.
  259. */
  260. var executeCommand = function(self, command, options, callback) {
  261. // Did the user destroy the topology
  262. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  263. // Get the db name we are executing against
  264. var dbName = options.dbName || options.authdb || self.s.databaseName;
  265. // If we have a readPreference set
  266. if(options.readPreference == null && self.s.readPreference) {
  267. options.readPreference = self.s.readPreference;
  268. }
  269. // Convert the readPreference if its not a write
  270. if(options.readPreference) {
  271. options.readPreference = convertReadPreference(options.readPreference);
  272. } else {
  273. options.readPreference = CoreReadPreference.primary;
  274. }
  275. // Debug information
  276. if(self.s.logger.isDebug()) self.s.logger.debug(f('executing command %s against %s with options [%s]'
  277. , JSON.stringify(command), f('%s.$cmd', dbName), JSON.stringify(debugOptions(debugFields, options))));
  278. // Execute command
  279. self.s.topology.command(f('%s.$cmd', dbName), command, options, function(err, result) {
  280. if(err) return handleCallback(callback, err);
  281. if(options.full) return handleCallback(callback, null, result);
  282. handleCallback(callback, null, result.result);
  283. });
  284. }
  285. /**
  286. * Execute a command
  287. * @method
  288. * @param {object} command The command hash
  289. * @param {object} [options=null] Optional settings.
  290. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  291. * @param {Db~resultCallback} [callback] The command result callback
  292. * @return {Promise} returns Promise if no callback passed
  293. */
  294. Db.prototype.command = function(command, options, callback) {
  295. var self = this;
  296. // Change the callback
  297. if(typeof options == 'function') callback = options, options = {};
  298. // Clone the options
  299. options = shallowClone(options);
  300. // Do we have a callback
  301. if(typeof callback == 'function') return executeCommand(self, command, options, callback);
  302. // Return a promise
  303. return new this.s.promiseLibrary(function(resolve, reject) {
  304. executeCommand(self, command, options, function(err, r) {
  305. if(err) return reject(err);
  306. resolve(r);
  307. });
  308. });
  309. }
  310. define.classMethod('command', {callback: true, promise:true});
  311. /**
  312. * The callback format for results
  313. * @callback Db~noResultCallback
  314. * @param {MongoError} error An error instance representing the error during the execution.
  315. * @param {null} result Is not set to a value
  316. */
  317. /**
  318. * Close the db and its underlying connections
  319. * @method
  320. * @param {boolean} force Force close, emitting no events
  321. * @param {Db~noResultCallback} [callback] The result callback
  322. * @return {Promise} returns Promise if no callback passed
  323. */
  324. Db.prototype.close = function(force, callback) {
  325. if(typeof force == 'function') callback = force, force = false;
  326. this.s.topology.close(force);
  327. var self = this;
  328. // Fire close event if any listeners
  329. if(this.listeners('close').length > 0) {
  330. this.emit('close');
  331. // If it's the top level db emit close on all children
  332. if(this.parentDb == null) {
  333. // Fire close on all children
  334. for(var i = 0; i < this.s.children.length; i++) {
  335. this.s.children[i].emit('close');
  336. }
  337. }
  338. // Remove listeners after emit
  339. self.removeAllListeners('close');
  340. }
  341. // Close parent db if set
  342. if(this.s.parentDb) this.s.parentDb.close();
  343. // Callback after next event loop tick
  344. if(typeof callback == 'function') return process.nextTick(function() {
  345. handleCallback(callback, null);
  346. })
  347. // Return dummy promise
  348. return new this.s.promiseLibrary(function(resolve) {
  349. resolve();
  350. });
  351. }
  352. define.classMethod('close', {callback: true, promise:true});
  353. /**
  354. * Return the Admin db instance
  355. * @method
  356. * @return {Admin} return the new Admin db instance
  357. */
  358. Db.prototype.admin = function() {
  359. return new Admin(this, this.s.topology, this.s.promiseLibrary);
  360. };
  361. define.classMethod('admin', {callback: false, promise:false, returns: [Admin]});
  362. /**
  363. * The callback format for the collection method, must be used if strict is specified
  364. * @callback Db~collectionResultCallback
  365. * @param {MongoError} error An error instance representing the error during the execution.
  366. * @param {Collection} collection The collection instance.
  367. */
  368. var collectionKeys = ['pkFactory', 'readPreference'
  369. , 'serializeFunctions', 'strict', 'readConcern', 'ignoreUndefined', 'promoteValues', 'promoteBuffers', 'promoteLongs'];
  370. /**
  371. * Fetch a specific collection (containing the actual collection information). If the application does not use strict mode you can
  372. * can use it without a callback in the following way: `var collection = db.collection('mycollection');`
  373. *
  374. * @method
  375. * @param {string} name the collection name we wish to access.
  376. * @param {object} [options=null] Optional settings.
  377. * @param {(number|string)} [options.w=null] The write concern.
  378. * @param {number} [options.wtimeout=null] The write concern timeout.
  379. * @param {boolean} [options.j=false] Specify a journal write concern.
  380. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  381. * @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
  382. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  383. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
  384. * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
  385. * @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
  386. * @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)
  387. * @param {Db~collectionResultCallback} callback The collection result callback
  388. * @return {Collection} return the new Collection instance if not in strict mode
  389. */
  390. Db.prototype.collection = function(name, options, callback) {
  391. var self = this;
  392. if(typeof options == 'function') callback = options, options = {};
  393. options = options || {};
  394. options = shallowClone(options);
  395. // Set the promise library
  396. options.promiseLibrary = this.s.promiseLibrary;
  397. // If we have not set a collection level readConcern set the db level one
  398. options.readConcern = options.readConcern || this.s.readConcern;
  399. // Do we have ignoreUndefined set
  400. if(this.s.options.ignoreUndefined) {
  401. options.ignoreUndefined = this.s.options.ignoreUndefined;
  402. }
  403. // Merge in all needed options and ensure correct writeConcern merging from db level
  404. options = mergeOptionsAndWriteConcern(options, this.s.options, collectionKeys, true);
  405. // Execute
  406. if(options == null || !options.strict) {
  407. try {
  408. var collection = new Collection(this, this.s.topology, this.s.databaseName, name, this.s.pkFactory, options);
  409. if(callback) callback(null, collection);
  410. return collection;
  411. } catch(err) {
  412. // if(err instanceof MongoError && callback) return callback(err);
  413. if(callback) return callback(err);
  414. throw err;
  415. }
  416. }
  417. // Strict mode
  418. if(typeof callback != 'function') {
  419. throw toError(f("A callback is required in strict mode. While getting collection %s.", name));
  420. }
  421. // Did the user destroy the topology
  422. if(self.serverConfig && self.serverConfig.isDestroyed()) {
  423. return callback(new MongoError('topology was destroyed'));
  424. }
  425. // Strict mode
  426. this.listCollections({name:name}, options).toArray(function(err, collections) {
  427. if(err != null) return handleCallback(callback, err, null);
  428. if(collections.length == 0) return handleCallback(callback, toError(f("Collection %s does not exist. Currently in strict mode.", name)), null);
  429. try {
  430. return handleCallback(callback, null, new Collection(self, self.s.topology, self.s.databaseName, name, self.s.pkFactory, options));
  431. } catch(err) {
  432. return handleCallback(callback, err, null);
  433. }
  434. });
  435. }
  436. define.classMethod('collection', {callback: true, promise:false, returns: [Collection]});
  437. function decorateWithWriteConcern(command, self, options) {
  438. // Do we support write concerns 3.4 and higher
  439. if(self.s.topology.capabilities().commandsTakeWriteConcern) {
  440. // Get the write concern settings
  441. var finalOptions = writeConcern(shallowClone(options), self, options);
  442. // Add the write concern to the command
  443. if(finalOptions.writeConcern) {
  444. command.writeConcern = finalOptions.writeConcern;
  445. }
  446. }
  447. }
  448. var createCollection = function(self, name, options, callback) {
  449. // Get the write concern options
  450. var finalOptions = writeConcern(shallowClone(options), self, options);
  451. // Did the user destroy the topology
  452. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  453. // Check if we have the name
  454. self.listCollections({name: name})
  455. .setReadPreference(ReadPreference.PRIMARY)
  456. .toArray(function(err, collections) {
  457. if(err != null) return handleCallback(callback, err, null);
  458. if(collections.length > 0 && finalOptions.strict) {
  459. return handleCallback(callback, MongoError.create({message: f("Collection %s already exists. Currently in strict mode.", name), driver:true}), null);
  460. } else if (collections.length > 0) {
  461. try { return handleCallback(callback, null, new Collection(self, self.s.topology, self.s.databaseName, name, self.s.pkFactory, options)); }
  462. catch(err) { return handleCallback(callback, err); }
  463. }
  464. // Create collection command
  465. var cmd = {'create':name};
  466. // Decorate command with writeConcern if supported
  467. decorateWithWriteConcern(cmd, self, options);
  468. // Add all optional parameters
  469. for(var n in options) {
  470. if(options[n] != null
  471. && typeof options[n] != 'function' && illegalCommandFields.indexOf(n) == -1) {
  472. cmd[n] = options[n];
  473. }
  474. }
  475. // Force a primary read Preference
  476. finalOptions.readPreference = ReadPreference.PRIMARY;
  477. // Execute command
  478. self.command(cmd, finalOptions, function(err) {
  479. if(err) return handleCallback(callback, err);
  480. handleCallback(callback, null, new Collection(self, self.s.topology, self.s.databaseName, name, self.s.pkFactory, options));
  481. });
  482. });
  483. }
  484. /**
  485. * Create a new collection on a server with the specified options. Use this to create capped collections.
  486. * More information about command options available at https://docs.mongodb.com/manual/reference/command/create/
  487. *
  488. * @method
  489. * @param {string} name the collection name we wish to access.
  490. * @param {object} [options=null] Optional settings.
  491. * @param {(number|string)} [options.w=null] The write concern.
  492. * @param {number} [options.wtimeout=null] The write concern timeout.
  493. * @param {boolean} [options.j=false] Specify a journal write concern.
  494. * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
  495. * @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
  496. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  497. * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
  498. * @param {boolean} [options.strict=false] Returns an error if the collection does not exist
  499. * @param {boolean} [options.capped=false] Create a capped collection.
  500. * @param {boolean} [options.autoIndexId=true] Create an index on the _id field of the document, True by default on MongoDB 2.2 or higher off for version < 2.2.
  501. * @param {number} [options.size=null] The size of the capped collection in bytes.
  502. * @param {number} [options.max=null] The maximum number of documents in the capped collection.
  503. * @param {number} [options.flags=null] Optional. Available for the MMAPv1 storage engine only to set the usePowerOf2Sizes and the noPadding flag.
  504. * @param {object} [options.storageEngine=null] Allows users to specify configuration to the storage engine on a per-collection basis when creating a collection on MongoDB 3.0 or higher.
  505. * @param {object} [options.validator=null] Allows users to specify validation rules or expressions for the collection. For more information, see Document Validation on MongoDB 3.2 or higher.
  506. * @param {string} [options.validationLevel=null] Determines how strictly MongoDB applies the validation rules to existing documents during an update on MongoDB 3.2 or higher.
  507. * @param {string} [options.validationAction=null] 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.
  508. * @param {object} [options.indexOptionDefaults=null] Allows users to specify a default configuration for indexes when creating a collection on MongoDB 3.2 or higher.
  509. * @param {string} [options.viewOn=null] 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.
  510. * @param {array} [options.pipeline=null] 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.
  511. * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
  512. * @param {Db~collectionResultCallback} [callback] The results callback
  513. * @return {Promise} returns Promise if no callback passed
  514. */
  515. Db.prototype.createCollection = function(name, options, callback) {
  516. var self = this;
  517. var args = Array.prototype.slice.call(arguments, 0);
  518. callback = args.pop();
  519. if(typeof callback != 'function') args.push(callback);
  520. name = args.length ? args.shift() : null;
  521. options = args.length ? args.shift() || {} : {};
  522. // Do we have a promisesLibrary
  523. options.promiseLibrary = options.promiseLibrary || this.s.promiseLibrary;
  524. // Check if the callback is in fact a string
  525. if(typeof callback == 'string') name = callback;
  526. // Execute the fallback callback
  527. if(typeof callback == 'function') return createCollection(self, name, options, callback);
  528. return new this.s.promiseLibrary(function(resolve, reject) {
  529. createCollection(self, name, options, function(err, r) {
  530. if(err) return reject(err);
  531. resolve(r);
  532. });
  533. });
  534. }
  535. define.classMethod('createCollection', {callback: true, promise:true});
  536. /**
  537. * Get all the db statistics.
  538. *
  539. * @method
  540. * @param {object} [options=null] Optional settings.
  541. * @param {number} [options.scale=null] Divide the returned sizes by scale value.
  542. * @param {Db~resultCallback} [callback] The collection result callback
  543. * @return {Promise} returns Promise if no callback passed
  544. */
  545. Db.prototype.stats = function(options, callback) {
  546. if(typeof options == 'function') callback = options, options = {};
  547. options = options || {};
  548. // Build command object
  549. var commandObject = { dbStats:true };
  550. // Check if we have the scale value
  551. if(options['scale'] != null) commandObject['scale'] = options['scale'];
  552. // If we have a readPreference set
  553. if(options.readPreference == null && this.s.readPreference) {
  554. options.readPreference = this.s.readPreference;
  555. }
  556. // Execute the command
  557. return this.command(commandObject, options, callback);
  558. }
  559. define.classMethod('stats', {callback: true, promise:true});
  560. // Transformation methods for cursor results
  561. var listCollectionsTranforms = function(databaseName) {
  562. var matching = f('%s.', databaseName);
  563. return {
  564. doc: function(doc) {
  565. var index = doc.name.indexOf(matching);
  566. // Remove database name if available
  567. if(doc.name && index == 0) {
  568. doc.name = doc.name.substr(index + matching.length);
  569. }
  570. return doc;
  571. }
  572. }
  573. }
  574. /**
  575. * Get the list of all collection information for the specified db.
  576. *
  577. * @method
  578. * @param {object} filter Query to filter collections by
  579. * @param {object} [options=null] Optional settings.
  580. * @param {number} [options.batchSize=null] The batchSize for the returned command cursor or if pre 2.8 the systems batch collection
  581. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  582. * @return {CommandCursor}
  583. */
  584. Db.prototype.listCollections = function(filter, options) {
  585. filter = filter || {};
  586. options = options || {};
  587. // Shallow clone the object
  588. options = shallowClone(options);
  589. // Set the promise library
  590. options.promiseLibrary = this.s.promiseLibrary;
  591. // Ensure valid readPreference
  592. if(options.readPreference) {
  593. options.readPreference = convertReadPreference(options.readPreference);
  594. }
  595. // We have a list collections command
  596. if(this.serverConfig.capabilities().hasListCollectionsCommand) {
  597. // Cursor options
  598. var cursor = options.batchSize ? {batchSize: options.batchSize} : {}
  599. // Build the command
  600. var command = { listCollections : true, filter: filter, cursor: cursor };
  601. // Set the AggregationCursor constructor
  602. options.cursorFactory = CommandCursor;
  603. // Create the cursor
  604. cursor = this.s.topology.cursor(f('%s.$cmd', this.s.databaseName), command, options);
  605. // Do we have a readPreference, apply it
  606. if(options.readPreference) {
  607. cursor.setReadPreference(options.readPreference);
  608. }
  609. // Return the cursor
  610. return cursor;
  611. }
  612. // We cannot use the listCollectionsCommand
  613. if(!this.serverConfig.capabilities().hasListCollectionsCommand) {
  614. // If we have legacy mode and have not provided a full db name filter it
  615. if(typeof filter.name == 'string' && !(new RegExp('^' + this.databaseName + '\\.').test(filter.name))) {
  616. filter = shallowClone(filter);
  617. filter.name = f('%s.%s', this.s.databaseName, filter.name);
  618. }
  619. }
  620. // No filter, filter by current database
  621. if(filter == null) {
  622. filter.name = f('/%s/', this.s.databaseName);
  623. }
  624. // Rewrite the filter to use $and to filter out indexes
  625. if(filter.name) {
  626. filter = {$and: [{name: filter.name}, {name:/^((?!\$).)*$/}]};
  627. } else {
  628. filter = {name:/^((?!\$).)*$/};
  629. }
  630. // Return options
  631. var _options = {transforms: listCollectionsTranforms(this.s.databaseName)}
  632. // Get the cursor
  633. cursor = this.collection(Db.SYSTEM_NAMESPACE_COLLECTION).find(filter, _options);
  634. // Do we have a readPreference, apply it
  635. if(options.readPreference) cursor.setReadPreference(options.readPreference);
  636. // Set the passed in batch size if one was provided
  637. if(options.batchSize) cursor = cursor.batchSize(options.batchSize);
  638. // We have a fallback mode using legacy systems collections
  639. return cursor;
  640. };
  641. define.classMethod('listCollections', {callback: false, promise:false, returns: [CommandCursor]});
  642. var evaluate = function(self, code, parameters, options, callback) {
  643. var finalCode = code;
  644. var finalParameters = [];
  645. // Did the user destroy the topology
  646. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  647. // If not a code object translate to one
  648. if(!(finalCode && finalCode._bsontype == 'Code')) finalCode = new Code(finalCode);
  649. // Ensure the parameters are correct
  650. if(parameters != null && !Array.isArray(parameters) && typeof parameters !== 'function') {
  651. finalParameters = [parameters];
  652. } else if(parameters != null && Array.isArray(parameters) && typeof parameters !== 'function') {
  653. finalParameters = parameters;
  654. }
  655. // Create execution selector
  656. var cmd = {'$eval':finalCode, 'args':finalParameters};
  657. // Check if the nolock parameter is passed in
  658. if(options['nolock']) {
  659. cmd['nolock'] = options['nolock'];
  660. }
  661. // Set primary read preference
  662. options.readPreference = new CoreReadPreference(ReadPreference.PRIMARY);
  663. // Execute the command
  664. self.command(cmd, options, function(err, result) {
  665. if(err) return handleCallback(callback, err, null);
  666. if(result && result.ok == 1) return handleCallback(callback, null, result.retval);
  667. if(result) return handleCallback(callback, MongoError.create({message: f("eval failed: %s", result.errmsg), driver:true}), null);
  668. handleCallback(callback, err, result);
  669. });
  670. }
  671. /**
  672. * Evaluate JavaScript on the server
  673. *
  674. * @method
  675. * @param {Code} code JavaScript to execute on server.
  676. * @param {(object|array)} parameters The parameters for the call.
  677. * @param {object} [options=null] Optional settings.
  678. * @param {boolean} [options.nolock=false] Tell MongoDB not to block on the evaluation of the javascript.
  679. * @param {Db~resultCallback} [callback] The results callback
  680. * @deprecated Eval is deprecated on MongoDB 3.2 and forward
  681. * @return {Promise} returns Promise if no callback passed
  682. */
  683. Db.prototype.eval = function(code, parameters, options, callback) {
  684. var self = this;
  685. var args = Array.prototype.slice.call(arguments, 1);
  686. callback = args.pop();
  687. if(typeof callback != 'function') args.push(callback);
  688. parameters = args.length ? args.shift() : parameters;
  689. options = args.length ? args.shift() || {} : {};
  690. // Check if the callback is in fact a string
  691. if(typeof callback == 'function') return evaluate(self, code, parameters, options, callback);
  692. // Execute the command
  693. return new this.s.promiseLibrary(function(resolve, reject) {
  694. evaluate(self, code, parameters, options, function(err, r) {
  695. if(err) return reject(err);
  696. resolve(r);
  697. });
  698. });
  699. };
  700. define.classMethod('eval', {callback: true, promise:true});
  701. /**
  702. * Rename a collection.
  703. *
  704. * @method
  705. * @param {string} fromCollection Name of current collection to rename.
  706. * @param {string} toCollection New name of of the collection.
  707. * @param {object} [options=null] Optional settings.
  708. * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
  709. * @param {Db~collectionResultCallback} [callback] The results callback
  710. * @return {Promise} returns Promise if no callback passed
  711. */
  712. Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) {
  713. var self = this;
  714. if(typeof options == 'function') callback = options, options = {};
  715. options = options || {};
  716. // Add return new collection
  717. options.new_collection = true;
  718. // Check if the callback is in fact a string
  719. if(typeof callback == 'function') {
  720. return this.collection(fromCollection).rename(toCollection, options, callback);
  721. }
  722. // Return a promise
  723. return new this.s.promiseLibrary(function(resolve, reject) {
  724. self.collection(fromCollection).rename(toCollection, options, function(err, r) {
  725. if(err) return reject(err);
  726. resolve(r);
  727. });
  728. });
  729. };
  730. define.classMethod('renameCollection', {callback: true, promise:true});
  731. /**
  732. * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
  733. *
  734. * @method
  735. * @param {string} name Name of collection to drop
  736. * @param {Db~resultCallback} [callback] The results callback
  737. * @return {Promise} returns Promise if no callback passed
  738. */
  739. Db.prototype.dropCollection = function(name, options, callback) {
  740. var self = this;
  741. if(typeof options == 'function') callback = options, options = {};
  742. options = options || {};
  743. // Command to execute
  744. var cmd = {'drop':name}
  745. // Decorate with write concern
  746. decorateWithWriteConcern(cmd, self, options);
  747. // options
  748. options = assign({}, this.s.options, {readPreference: ReadPreference.PRIMARY});
  749. // Check if the callback is in fact a string
  750. if(typeof callback == 'function') return this.command(cmd, options, function(err, result) {
  751. // Did the user destroy the topology
  752. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  753. if(err) return handleCallback(callback, err);
  754. if(result.ok) return handleCallback(callback, null, true);
  755. handleCallback(callback, null, false);
  756. });
  757. // Clone the options
  758. options = shallowClone(self.s.options);
  759. // Set readPreference PRIMARY
  760. options.readPreference = ReadPreference.PRIMARY;
  761. // Execute the command
  762. return new this.s.promiseLibrary(function(resolve, reject) {
  763. // Execute command
  764. self.command(cmd, options, function(err, result) {
  765. // Did the user destroy the topology
  766. if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
  767. if(err) return reject(err);
  768. if(result.ok) return resolve(true);
  769. resolve(false);
  770. });
  771. });
  772. };
  773. define.classMethod('dropCollection', {callback: true, promise:true});
  774. /**
  775. * Drop a database, removing it permanently from the server.
  776. *
  777. * @method
  778. * @param {Db~resultCallback} [callback] The results callback
  779. * @return {Promise} returns Promise if no callback passed
  780. */
  781. Db.prototype.dropDatabase = function(options, callback) {
  782. var self = this;
  783. if(typeof options == 'function') callback = options, options = {};
  784. options = options || {};
  785. // Drop database command
  786. var cmd = {'dropDatabase':1};
  787. // Decorate with write concern
  788. decorateWithWriteConcern(cmd, self, options);
  789. // Ensure primary only
  790. options = assign({}, this.s.options, {readPreference: ReadPreference.PRIMARY});
  791. // Check if the callback is in fact a string
  792. if(typeof callback == 'function') return this.command(cmd, options, function(err, result) {
  793. // Did the user destroy the topology
  794. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  795. if(callback == null) return;
  796. if(err) return handleCallback(callback, err, null);
  797. handleCallback(callback, null, result.ok ? true : false);
  798. });
  799. // Execute the command
  800. return new this.s.promiseLibrary(function(resolve, reject) {
  801. // Execute command
  802. self.command(cmd, options, function(err, result) {
  803. // Did the user destroy the topology
  804. if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
  805. if(err) return reject(err);
  806. if(result.ok) return resolve(true);
  807. resolve(false);
  808. });
  809. });
  810. }
  811. define.classMethod('dropDatabase', {callback: true, promise:true});
  812. /**
  813. * The callback format for the collections method.
  814. * @callback Db~collectionsResultCallback
  815. * @param {MongoError} error An error instance representing the error during the execution.
  816. * @param {Collection[]} collections An array of all the collections objects for the db instance.
  817. */
  818. var collections = function(self, callback) {
  819. // Let's get the collection names
  820. self.listCollections().toArray(function(err, documents) {
  821. if(err != null) return handleCallback(callback, err, null);
  822. // Filter collections removing any illegal ones
  823. documents = documents.filter(function(doc) {
  824. return doc.name.indexOf('$') == -1;
  825. });
  826. // Return the collection objects
  827. handleCallback(callback, null, documents.map(function(d) {
  828. return new Collection(self, self.s.topology, self.s.databaseName, d.name, self.s.pkFactory, self.s.options);
  829. }));
  830. });
  831. }
  832. /**
  833. * Fetch all collections for the current db.
  834. *
  835. * @method
  836. * @param {Db~collectionsResultCallback} [callback] The results callback
  837. * @return {Promise} returns Promise if no callback passed
  838. */
  839. Db.prototype.collections = function(callback) {
  840. var self = this;
  841. // Return the callback
  842. if(typeof callback == 'function') return collections(self, callback);
  843. // Return the promise
  844. return new self.s.promiseLibrary(function(resolve, reject) {
  845. collections(self, function(err, r) {
  846. if(err) return reject(err);
  847. resolve(r);
  848. });
  849. });
  850. };
  851. define.classMethod('collections', {callback: true, promise:true});
  852. /**
  853. * Runs a command on the database as admin.
  854. * @method
  855. * @param {object} command The command hash
  856. * @param {object} [options=null] Optional settings.
  857. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  858. * @param {Db~resultCallback} [callback] The command result callback
  859. * @return {Promise} returns Promise if no callback passed
  860. */
  861. Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
  862. var self = this;
  863. if(typeof options == 'function') callback = options, options = {};
  864. options = options || {};
  865. // Return the callback
  866. if(typeof callback == 'function') {
  867. // Convert read preference
  868. if(options.readPreference) {
  869. options.readPreference = convertReadPreference(options.readPreference)
  870. }
  871. return self.s.topology.command('admin.$cmd', selector, options, function(err, result) {
  872. // Did the user destroy the topology
  873. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  874. if(err) return handleCallback(callback, err);
  875. handleCallback(callback, null, result.result);
  876. });
  877. }
  878. // Return promise
  879. return new self.s.promiseLibrary(function(resolve, reject) {
  880. self.s.topology.command('admin.$cmd', selector, options, function(err, result) {
  881. // Did the user destroy the topology
  882. if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
  883. if(err) return reject(err);
  884. resolve(result.result);
  885. });
  886. });
  887. };
  888. define.classMethod('executeDbAdminCommand', {callback: true, promise:true});
  889. /**
  890. * Creates an index on the db and collection collection.
  891. * @method
  892. * @param {string} name Name of the collection to create the index on.
  893. * @param {(string|object)} fieldOrSpec Defines the index.
  894. * @param {object} [options=null] Optional settings.
  895. * @param {(number|string)} [options.w=null] The write concern.
  896. * @param {number} [options.wtimeout=null] The write concern timeout.
  897. * @param {boolean} [options.j=false] Specify a journal write concern.
  898. * @param {boolean} [options.unique=false] Creates an unique index.
  899. * @param {boolean} [options.sparse=false] Creates a sparse index.
  900. * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
  901. * @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
  902. * @param {number} [options.min=null] For geospatial indexes set the lower bound for the co-ordinates.
  903. * @param {number} [options.max=null] For geospatial indexes set the high bound for the co-ordinates.
  904. * @param {number} [options.v=null] Specify the format version of the indexes.
  905. * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
  906. * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
  907. * @param {object} [options.partialFilterExpression=null] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
  908. * @param {Db~resultCallback} [callback] The command result callback
  909. * @return {Promise} returns Promise if no callback passed
  910. */
  911. Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
  912. var self = this;
  913. var args = Array.prototype.slice.call(arguments, 2);
  914. callback = args.pop();
  915. if(typeof callback != 'function') args.push(callback);
  916. options = args.length ? args.shift() || {} : {};
  917. options = typeof callback === 'function' ? options : callback;
  918. options = options == null ? {} : options;
  919. // Shallow clone the options
  920. options = shallowClone(options);
  921. // If we have a callback fallback
  922. if(typeof callback == 'function') return createIndex(self, name, fieldOrSpec, options, callback);
  923. // Return a promise
  924. return new this.s.promiseLibrary(function(resolve, reject) {
  925. createIndex(self, name, fieldOrSpec, options, function(err, r) {
  926. if(err) return reject(err);
  927. resolve(r);
  928. });
  929. });
  930. };
  931. var createIndex = function(self, name, fieldOrSpec, options, callback) {
  932. // Get the write concern options
  933. var finalOptions = writeConcern({}, self, options, { readPreference: ReadPreference.PRIMARY });
  934. // Ensure we have a callback
  935. if(finalOptions.writeConcern && typeof callback != 'function') {
  936. throw MongoError.create({message: "Cannot use a writeConcern without a provided callback", driver:true});
  937. }
  938. // Run only against primary
  939. options.readPreference = ReadPreference.PRIMARY;
  940. // Did the user destroy the topology
  941. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  942. // Attempt to run using createIndexes command
  943. createIndexUsingCreateIndexes(self, name, fieldOrSpec, options, function(err, result) {
  944. if(err == null) return handleCallback(callback, err, result);
  945. // 67 = 'CannotCreateIndex' (malformed index options)
  946. // 85 = 'IndexOptionsConflict' (index already exists with different options)
  947. // 11000 = 'DuplicateKey' (couldn't build unique index because of dupes)
  948. // 11600 = 'InterruptedAtShutdown' (interrupted at shutdown)
  949. // These errors mean that the server recognized `createIndex` as a command
  950. // and so we don't need to fallback to an insert.
  951. if(err.code === 67 || err.code == 11000 || err.code === 85 || err.code == 11600) {
  952. return handleCallback(callback, err, result);
  953. }
  954. // Create command
  955. var doc = createCreateIndexCommand(self, name, fieldOrSpec, options);
  956. // Set no key checking
  957. finalOptions.checkKeys = false;
  958. // Insert document
  959. self.s.topology.insert(f("%s.%s", self.s.databaseName, Db.SYSTEM_INDEX_COLLECTION), doc, finalOptions, function(err, result) {
  960. if(callback == null) return;
  961. if(err) return handleCallback(callback, err);
  962. if(result == null) return handleCallback(callback, null, null);
  963. if(result.result.writeErrors) return handleCallback(callback, MongoError.create(result.result.writeErrors[0]), null);
  964. handleCallback(callback, null, doc.name);
  965. });
  966. });
  967. }
  968. define.classMethod('createIndex', {callback: true, promise:true});
  969. /**
  970. * Ensures that an index exists, if it does not it creates it
  971. * @method
  972. * @deprecated since version 2.0
  973. * @param {string} name The index name
  974. * @param {(string|object)} fieldOrSpec Defines the index.
  975. * @param {object} [options=null] Optional settings.
  976. * @param {(number|string)} [options.w=null] The write concern.
  977. * @param {number} [options.wtimeout=null] The write concern timeout.
  978. * @param {boolean} [options.j=false] Specify a journal write concern.
  979. * @param {boolean} [options.unique=false] Creates an unique index.
  980. * @param {boolean} [options.sparse=false] Creates a sparse index.
  981. * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
  982. * @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
  983. * @param {number} [options.min=null] For geospatial indexes set the lower bound for the co-ordinates.
  984. * @param {number} [options.max=null] For geospatial indexes set the high bound for the co-ordinates.
  985. * @param {number} [options.v=null] Specify the format version of the indexes.
  986. * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
  987. * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
  988. * @param {Db~resultCallback} [callback] The command result callback
  989. * @return {Promise} returns Promise if no callback passed
  990. */
  991. Db.prototype.ensureIndex = function(name, fieldOrSpec, options, callback) {
  992. var self = this;
  993. if(typeof options == 'function') callback = options, options = {};
  994. options = options || {};
  995. // If we have a callback fallback
  996. if(typeof callback == 'function') return ensureIndex(self, name, fieldOrSpec, options, callback);
  997. // Return a promise
  998. return new this.s.promiseLibrary(function(resolve, reject) {
  999. ensureIndex(self, name, fieldOrSpec, options, function(err, r) {
  1000. if(err) return reject(err);
  1001. resolve(r);
  1002. });
  1003. });
  1004. };
  1005. var ensureIndex = function(self, name, fieldOrSpec, options, callback) {
  1006. // Get the write concern options
  1007. var finalOptions = writeConcern({}, self, options);
  1008. // Create command
  1009. var selector = createCreateIndexCommand(self, name, fieldOrSpec, options);
  1010. var index_name = selector.name;
  1011. // Did the user destroy the topology
  1012. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1013. // Merge primary readPreference
  1014. finalOptions.readPreference = ReadPreference.PRIMARY
  1015. // Check if the index already exists
  1016. self.indexInformation(name, finalOptions, function(err, indexInformation) {
  1017. if(err != null && err.code != 26) return handleCallback(callback, err, null);
  1018. // If the index does not exist, create it
  1019. if(indexInformation == null || !indexInformation[index_name]) {
  1020. self.createIndex(name, fieldOrSpec, options, callback);
  1021. } else {
  1022. if(typeof callback === 'function') return handleCallback(callback, null, index_name);
  1023. }
  1024. });
  1025. }
  1026. define.classMethod('ensureIndex', {callback: true, promise:true});
  1027. Db.prototype.addChild = function(db) {
  1028. if(this.s.parentDb) return this.s.parentDb.addChild(db);
  1029. this.s.children.push(db);
  1030. }
  1031. /**
  1032. * Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
  1033. * related in a parent-child relationship to the original instance so that events are correctly emitted on child
  1034. * db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
  1035. * You can control these behaviors with the options noListener and returnNonCachedInstance.
  1036. *
  1037. * @method
  1038. * @param {string} name The name of the database we want to use.
  1039. * @param {object} [options=null] Optional settings.
  1040. * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
  1041. * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
  1042. * @return {Db}
  1043. */
  1044. Db.prototype.db = function(dbName, options) {
  1045. options = options || {};
  1046. // Copy the options and add out internal override of the not shared flag
  1047. var finalOptions = assign({}, this.options, options);
  1048. // Do we have the db in the cache already
  1049. if(this.s.dbCache[dbName] && finalOptions.returnNonCachedInstance !== true) {
  1050. return this.s.dbCache[dbName];
  1051. }
  1052. // Add current db as parentDb
  1053. if(finalOptions.noListener == null || finalOptions.noListener == false) {
  1054. finalOptions.parentDb = this;
  1055. }
  1056. // Add promiseLibrary
  1057. finalOptions.promiseLibrary = this.s.promiseLibrary;
  1058. // Return the db object
  1059. var db = new Db(dbName, this.s.topology, finalOptions)
  1060. // Add as child
  1061. if(finalOptions.noListener == null || finalOptions.noListener == false) {
  1062. this.addChild(db);
  1063. }
  1064. // Add the db to the cache
  1065. this.s.dbCache[dbName] = db;
  1066. // Return the database
  1067. return db;
  1068. };
  1069. define.classMethod('db', {callback: false, promise:false, returns: [Db]});
  1070. var _executeAuthCreateUserCommand = function(self, username, password, options, callback) {
  1071. // Special case where there is no password ($external users)
  1072. if(typeof username == 'string'
  1073. && password != null && typeof password == 'object') {
  1074. options = password;
  1075. password = null;
  1076. }
  1077. // Unpack all options
  1078. if(typeof options == 'function') {
  1079. callback = options;
  1080. options = {};
  1081. }
  1082. // Error out if we digestPassword set
  1083. if(options.digestPassword != null) {
  1084. throw toError("The digestPassword option is not supported via add_user. Please use db.command('createUser', ...) instead for this option.");
  1085. }
  1086. // Get additional values
  1087. var customData = options.customData != null ? options.customData : {};
  1088. var roles = Array.isArray(options.roles) ? options.roles : [];
  1089. var maxTimeMS = typeof options.maxTimeMS == 'number' ? options.maxTimeMS : null;
  1090. // If not roles defined print deprecated message
  1091. if(roles.length == 0) {
  1092. console.log("Creating a user without roles is deprecated in MongoDB >= 2.6");
  1093. }
  1094. // Get the error options
  1095. var commandOptions = {writeCommand:true};
  1096. if(options['dbName']) commandOptions.dbName = options['dbName'];
  1097. // Add maxTimeMS to options if set
  1098. if(maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS;
  1099. // Check the db name and add roles if needed
  1100. if((self.databaseName.toLowerCase() == 'admin' || options.dbName == 'admin') && !Array.isArray(options.roles)) {
  1101. roles = ['root']
  1102. } else if(!Array.isArray(options.roles)) {
  1103. roles = ['dbOwner']
  1104. }
  1105. // Build the command to execute
  1106. var command = {
  1107. createUser: username
  1108. , customData: customData
  1109. , roles: roles
  1110. , digestPassword:false
  1111. }
  1112. // Apply write concern to command
  1113. command = writeConcern(command, self, options);
  1114. // Use node md5 generator
  1115. var md5 = crypto.createHash('md5');
  1116. // Generate keys used for authentication
  1117. md5.update(username + ":mongo:" + password);
  1118. var userPassword = md5.digest('hex');
  1119. // No password
  1120. if(typeof password == 'string') {
  1121. command.pwd = userPassword;
  1122. }
  1123. // Force write using primary
  1124. commandOptions.readPreference = ReadPreference.primary;
  1125. // Execute the command
  1126. self.command(command, commandOptions, function(err, result) {
  1127. if(err && err.ok == 0 && err.code == undefined) return handleCallback(callback, {code: -5000}, null);
  1128. if(err) return handleCallback(callback, err, null);
  1129. handleCallback(callback, !result.ok ? toError(result) : null
  1130. , result.ok ? [{user: username, pwd: ''}] : null);
  1131. })
  1132. }
  1133. var addUser = function(self, username, password, options, callback) {
  1134. // Did the user destroy the topology
  1135. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1136. // Attempt to execute auth command
  1137. _executeAuthCreateUserCommand(self, username, password, options, function(err, r) {
  1138. // We need to perform the backward compatible insert operation
  1139. if(err && err.code == -5000) {
  1140. var finalOptions = writeConcern(shallowClone(options), self, options);
  1141. // Use node md5 generator
  1142. var md5 = crypto.createHash('md5');
  1143. // Generate keys used for authentication
  1144. md5.update(username + ":mongo:" + password);
  1145. var userPassword = md5.digest('hex');
  1146. // If we have another db set
  1147. var db = options.dbName ? self.db(options.dbName) : self;
  1148. // Fetch a user collection
  1149. var collection = db.collection(Db.SYSTEM_USER_COLLECTION);
  1150. // Check if we are inserting the first user
  1151. collection.count({}, function(err, count) {
  1152. // We got an error (f.ex not authorized)
  1153. if(err != null) return handleCallback(callback, err, null);
  1154. // Check if the user exists and update i
  1155. collection.find({user: username}, {dbName: options['dbName']}).toArray(function(err) {
  1156. // We got an error (f.ex not authorized)
  1157. if(err != null) return handleCallback(callback, err, null);
  1158. // Add command keys
  1159. finalOptions.upsert = true;
  1160. // We have a user, let's update the password or upsert if not
  1161. collection.update({user: username},{$set: {user: username, pwd: userPassword}}, finalOptions, function(err) {
  1162. if(count == 0 && err) return handleCallback(callback, null, [{user:username, pwd:userPassword}]);
  1163. if(err) return handleCallback(callback, err, null)
  1164. handleCallback(callback, null, [{user:username, pwd:userPassword}]);
  1165. });
  1166. });
  1167. });
  1168. return;
  1169. }
  1170. if(err) return handleCallback(callback, err);
  1171. handleCallback(callback, err, r);
  1172. });
  1173. }
  1174. /**
  1175. * Add a user to the database.
  1176. * @method
  1177. * @param {string} username The username.
  1178. * @param {string} password The password.
  1179. * @param {object} [options=null] Optional settings.
  1180. * @param {(number|string)} [options.w=null] The write concern.
  1181. * @param {number} [options.wtimeout=null] The write concern timeout.
  1182. * @param {boolean} [options.j=false] Specify a journal write concern.
  1183. * @param {object} [options.customData=null] Custom data associated with the user (only Mongodb 2.6 or higher)
  1184. * @param {object[]} [options.roles=null] Roles associated with the created user (only Mongodb 2.6 or higher)
  1185. * @param {Db~resultCallback} [callback] The command result callback
  1186. * @return {Promise} returns Promise if no callback passed
  1187. */
  1188. Db.prototype.addUser = function(username, password, options, callback) {
  1189. // Unpack the parameters
  1190. var self = this;
  1191. var args = Array.prototype.slice.call(arguments, 2);
  1192. callback = args.pop();
  1193. if(typeof callback != 'function') args.push(callback);
  1194. options = args.length ? args.shift() || {} : {};
  1195. // If we have a callback fallback
  1196. if(typeof callback == 'function') return addUser(self, username, password, options, callback);
  1197. // Return a promise
  1198. return new this.s.promiseLibrary(function(resolve, reject) {
  1199. addUser(self, username, password, options, function(err, r) {
  1200. if(err) return reject(err);
  1201. resolve(r);
  1202. });
  1203. });
  1204. };
  1205. define.classMethod('addUser', {callback: true, promise:true});
  1206. var _executeAuthRemoveUserCommand = function(self, username, options, callback) {
  1207. if(typeof options == 'function') callback = options, options = {};
  1208. // Did the user destroy the topology
  1209. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1210. // Get the error options
  1211. var commandOptions = {writeCommand:true};
  1212. if(options['dbName']) commandOptions.dbName = options['dbName'];
  1213. // Get additional values
  1214. var maxTimeMS = typeof options.maxTimeMS == 'number' ? options.maxTimeMS : null;
  1215. // Add maxTimeMS to options if set
  1216. if(maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS;
  1217. // Build the command to execute
  1218. var command = {
  1219. dropUser: username
  1220. }
  1221. // Apply write concern to command
  1222. command = writeConcern(command, self, options);
  1223. // Force write using primary
  1224. commandOptions.readPreference = ReadPreference.primary;
  1225. // Execute the command
  1226. self.command(command, commandOptions, function(err, result) {
  1227. if(err && !err.ok && err.code == undefined) return handleCallback(callback, {code: -5000});
  1228. if(err) return handleCallback(callback, err, null);
  1229. handleCallback(callback, null, result.ok ? true : false);
  1230. })
  1231. }
  1232. var removeUser = function(self, username, options, callback) {
  1233. // Attempt to execute command
  1234. _executeAuthRemoveUserCommand(self, username, options, function(err, result) {
  1235. if(err && err.code == -5000) {
  1236. var finalOptions = writeConcern(shallowClone(options), self, options);
  1237. // If we have another db set
  1238. var db = options.dbName ? self.db(options.dbName) : self;
  1239. // Fetch a user collection
  1240. var collection = db.collection(Db.SYSTEM_USER_COLLECTION);
  1241. // Locate the user
  1242. collection.findOne({user: username}, {}, function(err, user) {
  1243. if(user == null) return handleCallback(callback, err, false);
  1244. collection.remove({user: username}, finalOptions, function(err) {
  1245. handleCallback(callback, err, true);
  1246. });
  1247. });
  1248. return;
  1249. }
  1250. if(err) return handleCallback(callback, err);
  1251. handleCallback(callback, err, result);
  1252. });
  1253. }
  1254. define.classMethod('removeUser', {callback: true, promise:true});
  1255. /**
  1256. * Remove a user from a database
  1257. * @method
  1258. * @param {string} username The username.
  1259. * @param {object} [options=null] Optional settings.
  1260. * @param {(number|string)} [options.w=null] The write concern.
  1261. * @param {number} [options.wtimeout=null] The write concern timeout.
  1262. * @param {boolean} [options.j=false] Specify a journal write concern.
  1263. * @param {Db~resultCallback} [callback] The command result callback
  1264. * @return {Promise} returns Promise if no callback passed
  1265. */
  1266. Db.prototype.removeUser = function(username, options, callback) {
  1267. // Unpack the parameters
  1268. var self = this;
  1269. var args = Array.prototype.slice.call(arguments, 1);
  1270. callback = args.pop();
  1271. if(typeof callback != 'function') args.push(callback);
  1272. options = args.length ? args.shift() || {} : {};
  1273. // If we have a callback fallback
  1274. if(typeof callback == 'function') return removeUser(self, username, options, callback);
  1275. // Return a promise
  1276. return new this.s.promiseLibrary(function(resolve, reject) {
  1277. removeUser(self, username, options, function(err, r) {
  1278. if(err) return reject(err);
  1279. resolve(r);
  1280. });
  1281. });
  1282. };
  1283. /**
  1284. * Authenticate a user against the server.
  1285. * @method
  1286. * @param {string} username The username.
  1287. * @param {string} [password] The password.
  1288. * @param {object} [options=null] Optional settings.
  1289. * @param {string} [options.authMechanism=MONGODB-CR] The authentication mechanism to use, GSSAPI, MONGODB-CR, MONGODB-X509, PLAIN
  1290. * @param {Db~resultCallback} [callback] The command result callback
  1291. * @return {Promise} returns Promise if no callback passed
  1292. * @deprecated This method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials.
  1293. */
  1294. Db.prototype.authenticate = function(username, password, options, callback) {
  1295. console.warn("Db.prototype.authenticate method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials.");
  1296. return authenticate.apply(this, [this].concat(Array.prototype.slice.call(arguments)));
  1297. };
  1298. define.classMethod('authenticate', {callback: true, promise:true});
  1299. /**
  1300. * Logout user from server, fire off on all connections and remove all auth info
  1301. * @method
  1302. * @param {object} [options=null] Optional settings.
  1303. * @param {string} [options.dbName=null] Logout against different database than current.
  1304. * @param {Db~resultCallback} [callback] The command result callback
  1305. * @return {Promise} returns Promise if no callback passed
  1306. */
  1307. Db.prototype.logout = function(options, callback) {
  1308. var self = this;
  1309. if(typeof options == 'function') callback = options, options = {};
  1310. options = options || {};
  1311. // Establish the correct database name
  1312. var dbName = this.s.authSource ? this.s.authSource : this.s.databaseName;
  1313. dbName = options.dbName ? options.dbName : dbName;
  1314. // If we have a callback
  1315. if(typeof callback == 'function') {
  1316. return self.s.topology.logout(dbName, function(err) {
  1317. if(err) return callback(err);
  1318. callback(null, true);
  1319. });
  1320. }
  1321. // Return a promise
  1322. return new this.s.promiseLibrary(function(resolve, reject) {
  1323. self.s.topology.logout(dbName, function(err) {
  1324. if(err) return reject(err);
  1325. resolve(true);
  1326. });
  1327. });
  1328. }
  1329. define.classMethod('logout', {callback: true, promise:true});
  1330. /**
  1331. * Retrieves this collections index info.
  1332. * @method
  1333. * @param {string} name The name of the collection.
  1334. * @param {object} [options=null] Optional settings.
  1335. * @param {boolean} [options.full=false] Returns the full raw index information.
  1336. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  1337. * @param {Db~resultCallback} [callback] The command result callback
  1338. * @return {Promise} returns Promise if no callback passed
  1339. */
  1340. Db.prototype.indexInformation = function(name, options, callback) {
  1341. var self = this;
  1342. if(typeof options == 'function') callback = options, options = {};
  1343. options = options || {};
  1344. // If we have a callback fallback
  1345. if(typeof callback == 'function') return indexInformation(self, name, options, callback);
  1346. // Return a promise
  1347. return new this.s.promiseLibrary(function(resolve, reject) {
  1348. indexInformation(self, name, options, function(err, r) {
  1349. if(err) return reject(err);
  1350. resolve(r);
  1351. });
  1352. });
  1353. };
  1354. var indexInformation = function(self, name, options, callback) {
  1355. // If we specified full information
  1356. var full = options['full'] == null ? false : options['full'];
  1357. // Did the user destroy the topology
  1358. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1359. // Process all the results from the index command and collection
  1360. var processResults = function(indexes) {
  1361. // Contains all the information
  1362. var info = {};
  1363. // Process all the indexes
  1364. for(var i = 0; i < indexes.length; i++) {
  1365. var index = indexes[i];
  1366. // Let's unpack the object
  1367. info[index.name] = [];
  1368. for(var name in index.key) {
  1369. info[index.name].push([name, index.key[name]]);
  1370. }
  1371. }
  1372. return info;
  1373. }
  1374. // Get the list of indexes of the specified collection
  1375. self.collection(name).listIndexes(options).toArray(function(err, indexes) {
  1376. if(err) return callback(toError(err));
  1377. if(!Array.isArray(indexes)) return handleCallback(callback, null, []);
  1378. if(full) return handleCallback(callback, null, indexes);
  1379. handleCallback(callback, null, processResults(indexes));
  1380. });
  1381. }
  1382. define.classMethod('indexInformation', {callback: true, promise:true});
  1383. var createCreateIndexCommand = function(db, name, fieldOrSpec, options) {
  1384. var indexParameters = parseIndexOptions(fieldOrSpec);
  1385. var fieldHash = indexParameters.fieldHash;
  1386. // Generate the index name
  1387. var indexName = typeof options.name == 'string' ? options.name : indexParameters.name;
  1388. var selector = {
  1389. 'ns': db.databaseName + "." + name, 'key': fieldHash, 'name': indexName
  1390. }
  1391. // Ensure we have a correct finalUnique
  1392. var finalUnique = options == null || 'object' === typeof options ? false : options;
  1393. // Set up options
  1394. options = options == null || typeof options == 'boolean' ? {} : options;
  1395. // Add all the options
  1396. var keysToOmit = Object.keys(selector);
  1397. for(var optionName in options) {
  1398. if(keysToOmit.indexOf(optionName) == -1) {
  1399. selector[optionName] = options[optionName];
  1400. }
  1401. }
  1402. if(selector['unique'] == null) selector['unique'] = finalUnique;
  1403. // Remove any write concern operations
  1404. var removeKeys = ['w', 'wtimeout', 'j', 'fsync', 'readPreference'];
  1405. for(var i = 0; i < removeKeys.length; i++) {
  1406. delete selector[removeKeys[i]];
  1407. }
  1408. // Return the command creation selector
  1409. return selector;
  1410. }
  1411. var createIndexUsingCreateIndexes = function(self, name, fieldOrSpec, options, callback) {
  1412. // Build the index
  1413. var indexParameters = parseIndexOptions(fieldOrSpec);
  1414. // Generate the index name
  1415. var indexName = typeof options.name == 'string' ? options.name : indexParameters.name;
  1416. // Set up the index
  1417. var indexes = [{ name: indexName, key: indexParameters.fieldHash }];
  1418. // merge all the options
  1419. var keysToOmit = Object.keys(indexes[0]);
  1420. for(var optionName in options) {
  1421. if(keysToOmit.indexOf(optionName) == -1) {
  1422. indexes[0][optionName] = options[optionName];
  1423. }
  1424. // Remove any write concern operations
  1425. var removeKeys = ['w', 'wtimeout', 'j', 'fsync', 'readPreference'];
  1426. for(var i = 0; i < removeKeys.length; i++) {
  1427. delete indexes[0][removeKeys[i]];
  1428. }
  1429. }
  1430. // Get capabilities
  1431. var capabilities = self.s.topology.capabilities();
  1432. // Did the user pass in a collation, check if our write server supports it
  1433. if(indexes[0].collation && capabilities && !capabilities.commandsTakeCollation) {
  1434. // Create a new error
  1435. var error = new MongoError(f('server/primary/mongos does not support collation'));
  1436. error.code = 67;
  1437. // Return the error
  1438. return callback(error);
  1439. }
  1440. // Create command, apply write concern to command
  1441. var cmd = writeConcern({createIndexes: name, indexes: indexes}, self, options);
  1442. // Decorate command with writeConcern if supported
  1443. decorateWithWriteConcern(cmd, self, options);
  1444. // ReadPreference primary
  1445. options.readPreference = ReadPreference.PRIMARY;
  1446. // Build the command
  1447. self.command(cmd, options, function(err, result) {
  1448. if(err) return handleCallback(callback, err, null);
  1449. if(result.ok == 0) return handleCallback(callback, toError(result), null);
  1450. // Return the indexName for backward compatibility
  1451. handleCallback(callback, null, indexName);
  1452. });
  1453. }
  1454. // Validate the database name
  1455. var validateDatabaseName = function(databaseName) {
  1456. if(typeof databaseName !== 'string') throw MongoError.create({message: "database name must be a string", driver:true});
  1457. if(databaseName.length === 0) throw MongoError.create({message: "database name cannot be the empty string", driver:true});
  1458. if(databaseName == '$external') return;
  1459. var invalidChars = [" ", ".", "$", "/", "\\"];
  1460. for(var i = 0; i < invalidChars.length; i++) {
  1461. if(databaseName.indexOf(invalidChars[i]) != -1) throw MongoError.create({message: "database names cannot contain the character '" + invalidChars[i] + "'", driver:true});
  1462. }
  1463. }
  1464. // Get write concern
  1465. var writeConcern = function(target, db, options) {
  1466. if(options.w != null || options.j != null || options.fsync != null) {
  1467. var opts = {};
  1468. if(options.w) opts.w = options.w;
  1469. if(options.wtimeout) opts.wtimeout = options.wtimeout;
  1470. if(options.j) opts.j = options.j;
  1471. if(options.fsync) opts.fsync = options.fsync;
  1472. target.writeConcern = opts;
  1473. } else if(db.writeConcern.w != null || db.writeConcern.j != null || db.writeConcern.fsync != null) {
  1474. target.writeConcern = db.writeConcern;
  1475. }
  1476. return target
  1477. }
  1478. // Add listeners to topology
  1479. var createListener = function(self, e, object) {
  1480. var listener = function(err) {
  1481. if(object.listeners(e).length > 0) {
  1482. object.emit(e, err, self);
  1483. // Emit on all associated db's if available
  1484. for(var i = 0; i < self.s.children.length; i++) {
  1485. self.s.children[i].emit(e, err, self.s.children[i]);
  1486. }
  1487. }
  1488. }
  1489. return listener;
  1490. }
  1491. /**
  1492. * Unref all sockets
  1493. * @method
  1494. */
  1495. Db.prototype.unref = function() {
  1496. this.s.topology.unref();
  1497. }
  1498. /**
  1499. * Db close event
  1500. *
  1501. * Emitted after a socket closed against a single server or mongos proxy.
  1502. *
  1503. * @event Db#close
  1504. * @type {MongoError}
  1505. */
  1506. /**
  1507. * Db authenticated event
  1508. *
  1509. * Emitted after all server members in the topology (single server, replicaset or mongos) have successfully authenticated.
  1510. *
  1511. * @event Db#authenticated
  1512. * @type {object}
  1513. */
  1514. /**
  1515. * Db reconnect event
  1516. *
  1517. * * Server: Emitted when the driver has reconnected and re-authenticated.
  1518. * * ReplicaSet: N/A
  1519. * * Mongos: Emitted when the driver reconnects and re-authenticates successfully against a Mongos.
  1520. *
  1521. * @event Db#reconnect
  1522. * @type {object}
  1523. */
  1524. /**
  1525. * Db error event
  1526. *
  1527. * Emitted after an error occurred against a single server or mongos proxy.
  1528. *
  1529. * @event Db#error
  1530. * @type {MongoError}
  1531. */
  1532. /**
  1533. * Db timeout event
  1534. *
  1535. * Emitted after a socket timeout occurred against a single server or mongos proxy.
  1536. *
  1537. * @event Db#timeout
  1538. * @type {MongoError}
  1539. */
  1540. /**
  1541. * Db parseError event
  1542. *
  1543. * The parseError event is emitted if the driver detects illegal or corrupt BSON being received from the server.
  1544. *
  1545. * @event Db#parseError
  1546. * @type {MongoError}
  1547. */
  1548. /**
  1549. * Db fullsetup event, emitted when all servers in the topology have been connected to at start up time.
  1550. *
  1551. * * Server: Emitted when the driver has connected to the single server and has authenticated.
  1552. * * ReplSet: Emitted after the driver has attempted to connect to all replicaset members.
  1553. * * Mongos: Emitted after the driver has attempted to connect to all mongos proxies.
  1554. *
  1555. * @event Db#fullsetup
  1556. * @type {Db}
  1557. */
  1558. // Constants
  1559. Db.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces";
  1560. Db.SYSTEM_INDEX_COLLECTION = "system.indexes";
  1561. Db.SYSTEM_PROFILE_COLLECTION = "system.profile";
  1562. Db.SYSTEM_USER_COLLECTION = "system.users";
  1563. Db.SYSTEM_COMMAND_COLLECTION = "$cmd";
  1564. Db.SYSTEM_JS_COLLECTION = "system.js";
  1565. module.exports = Db;