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://www.mongodb.com/docs/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. } else {
  595. options.readPreference = this.s.readPreference || CoreReadPreference.primary;
  596. }
  597. // We have a list collections command
  598. if(this.serverConfig.capabilities().hasListCollectionsCommand) {
  599. // Cursor options
  600. var cursor = options.batchSize ? {batchSize: options.batchSize} : {}
  601. // Build the command
  602. var command = { listCollections : true, filter: filter, cursor: cursor };
  603. // Set the AggregationCursor constructor
  604. options.cursorFactory = CommandCursor;
  605. // Create the cursor
  606. cursor = this.s.topology.cursor(f('%s.$cmd', this.s.databaseName), command, options);
  607. // Do we have a readPreference, apply it
  608. if(options.readPreference) {
  609. cursor.setReadPreference(options.readPreference);
  610. }
  611. // Return the cursor
  612. return cursor;
  613. }
  614. // We cannot use the listCollectionsCommand
  615. if(!this.serverConfig.capabilities().hasListCollectionsCommand) {
  616. // If we have legacy mode and have not provided a full db name filter it
  617. if(typeof filter.name == 'string' && !(new RegExp('^' + this.databaseName + '\\.').test(filter.name))) {
  618. filter = shallowClone(filter);
  619. filter.name = f('%s.%s', this.s.databaseName, filter.name);
  620. }
  621. }
  622. // No filter, filter by current database
  623. if(filter == null) {
  624. filter.name = f('/%s/', this.s.databaseName);
  625. }
  626. // Rewrite the filter to use $and to filter out indexes
  627. if(filter.name) {
  628. filter = {$and: [{name: filter.name}, {name:/^((?!\$).)*$/}]};
  629. } else {
  630. filter = {name:/^((?!\$).)*$/};
  631. }
  632. // Return options
  633. var _options = {transforms: listCollectionsTranforms(this.s.databaseName)}
  634. // Get the cursor
  635. cursor = this.collection(Db.SYSTEM_NAMESPACE_COLLECTION).find(filter, _options);
  636. // Do we have a readPreference, apply it
  637. if(options.readPreference) cursor.setReadPreference(options.readPreference);
  638. // Set the passed in batch size if one was provided
  639. if(options.batchSize) cursor = cursor.batchSize(options.batchSize);
  640. // We have a fallback mode using legacy systems collections
  641. return cursor;
  642. };
  643. define.classMethod('listCollections', {callback: false, promise:false, returns: [CommandCursor]});
  644. var evaluate = function(self, code, parameters, options, callback) {
  645. var finalCode = code;
  646. var finalParameters = [];
  647. // Did the user destroy the topology
  648. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  649. // If not a code object translate to one
  650. if(!(finalCode && finalCode._bsontype == 'Code')) finalCode = new Code(finalCode);
  651. // Ensure the parameters are correct
  652. if(parameters != null && !Array.isArray(parameters) && typeof parameters !== 'function') {
  653. finalParameters = [parameters];
  654. } else if(parameters != null && Array.isArray(parameters) && typeof parameters !== 'function') {
  655. finalParameters = parameters;
  656. }
  657. // Create execution selector
  658. var cmd = {'$eval':finalCode, 'args':finalParameters};
  659. // Check if the nolock parameter is passed in
  660. if(options['nolock']) {
  661. cmd['nolock'] = options['nolock'];
  662. }
  663. // Set primary read preference
  664. options.readPreference = new CoreReadPreference(ReadPreference.PRIMARY);
  665. // Execute the command
  666. self.command(cmd, options, function(err, result) {
  667. if(err) return handleCallback(callback, err, null);
  668. if(result && result.ok == 1) return handleCallback(callback, null, result.retval);
  669. if(result) return handleCallback(callback, MongoError.create({message: f("eval failed: %s", result.errmsg), driver:true}), null);
  670. handleCallback(callback, err, result);
  671. });
  672. }
  673. /**
  674. * Evaluate JavaScript on the server
  675. *
  676. * @method
  677. * @param {Code} code JavaScript to execute on server.
  678. * @param {(object|array)} parameters The parameters for the call.
  679. * @param {object} [options=null] Optional settings.
  680. * @param {boolean} [options.nolock=false] Tell MongoDB not to block on the evaluation of the javascript.
  681. * @param {Db~resultCallback} [callback] The results callback
  682. * @deprecated Eval is deprecated on MongoDB 3.2 and forward
  683. * @return {Promise} returns Promise if no callback passed
  684. */
  685. Db.prototype.eval = function(code, parameters, options, callback) {
  686. var self = this;
  687. var args = Array.prototype.slice.call(arguments, 1);
  688. callback = args.pop();
  689. if(typeof callback != 'function') args.push(callback);
  690. parameters = args.length ? args.shift() : parameters;
  691. options = args.length ? args.shift() || {} : {};
  692. // Check if the callback is in fact a string
  693. if(typeof callback == 'function') return evaluate(self, code, parameters, options, callback);
  694. // Execute the command
  695. return new this.s.promiseLibrary(function(resolve, reject) {
  696. evaluate(self, code, parameters, options, function(err, r) {
  697. if(err) return reject(err);
  698. resolve(r);
  699. });
  700. });
  701. };
  702. define.classMethod('eval', {callback: true, promise:true});
  703. /**
  704. * Rename a collection.
  705. *
  706. * @method
  707. * @param {string} fromCollection Name of current collection to rename.
  708. * @param {string} toCollection New name of of the collection.
  709. * @param {object} [options=null] Optional settings.
  710. * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
  711. * @param {Db~collectionResultCallback} [callback] The results callback
  712. * @return {Promise} returns Promise if no callback passed
  713. */
  714. Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) {
  715. var self = this;
  716. if(typeof options == 'function') callback = options, options = {};
  717. options = options || {};
  718. // Add return new collection
  719. options.new_collection = true;
  720. // Check if the callback is in fact a string
  721. if(typeof callback == 'function') {
  722. return this.collection(fromCollection).rename(toCollection, options, callback);
  723. }
  724. // Return a promise
  725. return new this.s.promiseLibrary(function(resolve, reject) {
  726. self.collection(fromCollection).rename(toCollection, options, function(err, r) {
  727. if(err) return reject(err);
  728. resolve(r);
  729. });
  730. });
  731. };
  732. define.classMethod('renameCollection', {callback: true, promise:true});
  733. /**
  734. * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
  735. *
  736. * @method
  737. * @param {string} name Name of collection to drop
  738. * @param {Db~resultCallback} [callback] The results callback
  739. * @return {Promise} returns Promise if no callback passed
  740. */
  741. Db.prototype.dropCollection = function(name, options, callback) {
  742. var self = this;
  743. if(typeof options == 'function') callback = options, options = {};
  744. options = options || {};
  745. // Command to execute
  746. var cmd = {'drop':name}
  747. // Decorate with write concern
  748. decorateWithWriteConcern(cmd, self, options);
  749. // options
  750. options = assign({}, this.s.options, {readPreference: ReadPreference.PRIMARY});
  751. // Check if the callback is in fact a string
  752. if(typeof callback == 'function') return this.command(cmd, options, function(err, result) {
  753. // Did the user destroy the topology
  754. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  755. if(err) return handleCallback(callback, err);
  756. if(result.ok) return handleCallback(callback, null, true);
  757. handleCallback(callback, null, false);
  758. });
  759. // Clone the options
  760. options = shallowClone(self.s.options);
  761. // Set readPreference PRIMARY
  762. options.readPreference = ReadPreference.PRIMARY;
  763. // Execute the command
  764. return new this.s.promiseLibrary(function(resolve, reject) {
  765. // Execute command
  766. self.command(cmd, options, function(err, result) {
  767. // Did the user destroy the topology
  768. if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
  769. if(err) return reject(err);
  770. if(result.ok) return resolve(true);
  771. resolve(false);
  772. });
  773. });
  774. };
  775. define.classMethod('dropCollection', {callback: true, promise:true});
  776. /**
  777. * Drop a database, removing it permanently from the server.
  778. *
  779. * @method
  780. * @param {Db~resultCallback} [callback] The results callback
  781. * @return {Promise} returns Promise if no callback passed
  782. */
  783. Db.prototype.dropDatabase = function(options, callback) {
  784. var self = this;
  785. if(typeof options == 'function') callback = options, options = {};
  786. options = options || {};
  787. // Drop database command
  788. var cmd = {'dropDatabase':1};
  789. // Decorate with write concern
  790. decorateWithWriteConcern(cmd, self, options);
  791. // Ensure primary only
  792. options = assign({}, this.s.options, {readPreference: ReadPreference.PRIMARY});
  793. // Check if the callback is in fact a string
  794. if(typeof callback == 'function') return this.command(cmd, options, function(err, result) {
  795. // Did the user destroy the topology
  796. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  797. if(callback == null) return;
  798. if(err) return handleCallback(callback, err, null);
  799. handleCallback(callback, null, result.ok ? true : false);
  800. });
  801. // Execute the command
  802. return new this.s.promiseLibrary(function(resolve, reject) {
  803. // Execute command
  804. self.command(cmd, options, function(err, result) {
  805. // Did the user destroy the topology
  806. if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
  807. if(err) return reject(err);
  808. if(result.ok) return resolve(true);
  809. resolve(false);
  810. });
  811. });
  812. }
  813. define.classMethod('dropDatabase', {callback: true, promise:true});
  814. /**
  815. * The callback format for the collections method.
  816. * @callback Db~collectionsResultCallback
  817. * @param {MongoError} error An error instance representing the error during the execution.
  818. * @param {Collection[]} collections An array of all the collections objects for the db instance.
  819. */
  820. var collections = function(self, callback) {
  821. // Let's get the collection names
  822. self.listCollections().toArray(function(err, documents) {
  823. if(err != null) return handleCallback(callback, err, null);
  824. // Filter collections removing any illegal ones
  825. documents = documents.filter(function(doc) {
  826. return doc.name.indexOf('$') == -1;
  827. });
  828. // Return the collection objects
  829. handleCallback(callback, null, documents.map(function(d) {
  830. return new Collection(self, self.s.topology, self.s.databaseName, d.name, self.s.pkFactory, self.s.options);
  831. }));
  832. });
  833. }
  834. /**
  835. * Fetch all collections for the current db.
  836. *
  837. * @method
  838. * @param {Db~collectionsResultCallback} [callback] The results callback
  839. * @return {Promise} returns Promise if no callback passed
  840. */
  841. Db.prototype.collections = function(callback) {
  842. var self = this;
  843. // Return the callback
  844. if(typeof callback == 'function') return collections(self, callback);
  845. // Return the promise
  846. return new self.s.promiseLibrary(function(resolve, reject) {
  847. collections(self, function(err, r) {
  848. if(err) return reject(err);
  849. resolve(r);
  850. });
  851. });
  852. };
  853. define.classMethod('collections', {callback: true, promise:true});
  854. /**
  855. * Runs a command on the database as admin.
  856. * @method
  857. * @param {object} command The command hash
  858. * @param {object} [options=null] Optional settings.
  859. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  860. * @param {Db~resultCallback} [callback] The command result callback
  861. * @return {Promise} returns Promise if no callback passed
  862. */
  863. Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
  864. var self = this;
  865. if(typeof options == 'function') callback = options, options = {};
  866. options = options || {};
  867. // Return the callback
  868. if(typeof callback == 'function') {
  869. // Convert read preference
  870. if(options.readPreference) {
  871. options.readPreference = convertReadPreference(options.readPreference)
  872. }
  873. return self.s.topology.command('admin.$cmd', selector, options, function(err, result) {
  874. // Did the user destroy the topology
  875. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  876. if(err) return handleCallback(callback, err);
  877. handleCallback(callback, null, result.result);
  878. });
  879. }
  880. // Return promise
  881. return new self.s.promiseLibrary(function(resolve, reject) {
  882. self.s.topology.command('admin.$cmd', selector, options, function(err, result) {
  883. // Did the user destroy the topology
  884. if(self.serverConfig && self.serverConfig.isDestroyed()) return reject(new MongoError('topology was destroyed'));
  885. if(err) return reject(err);
  886. resolve(result.result);
  887. });
  888. });
  889. };
  890. define.classMethod('executeDbAdminCommand', {callback: true, promise:true});
  891. /**
  892. * Creates an index on the db and collection collection.
  893. * @method
  894. * @param {string} name Name of the collection to create the index on.
  895. * @param {(string|object)} fieldOrSpec Defines the index.
  896. * @param {object} [options=null] Optional settings.
  897. * @param {(number|string)} [options.w=null] The write concern.
  898. * @param {number} [options.wtimeout=null] The write concern timeout.
  899. * @param {boolean} [options.j=false] Specify a journal write concern.
  900. * @param {boolean} [options.unique=false] Creates an unique index.
  901. * @param {boolean} [options.sparse=false] Creates a sparse index.
  902. * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
  903. * @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
  904. * @param {number} [options.min=null] For geospatial indexes set the lower bound for the co-ordinates.
  905. * @param {number} [options.max=null] For geospatial indexes set the high bound for the co-ordinates.
  906. * @param {number} [options.v=null] Specify the format version of the indexes.
  907. * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
  908. * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
  909. * @param {object} [options.partialFilterExpression=null] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
  910. * @param {Db~resultCallback} [callback] The command result callback
  911. * @return {Promise} returns Promise if no callback passed
  912. */
  913. Db.prototype.createIndex = function(name, fieldOrSpec, options, callback) {
  914. var self = this;
  915. var args = Array.prototype.slice.call(arguments, 2);
  916. callback = args.pop();
  917. if(typeof callback != 'function') args.push(callback);
  918. options = args.length ? args.shift() || {} : {};
  919. options = typeof callback === 'function' ? options : callback;
  920. options = options == null ? {} : options;
  921. // Shallow clone the options
  922. options = shallowClone(options);
  923. // If we have a callback fallback
  924. if(typeof callback == 'function') return createIndex(self, name, fieldOrSpec, options, callback);
  925. // Return a promise
  926. return new this.s.promiseLibrary(function(resolve, reject) {
  927. createIndex(self, name, fieldOrSpec, options, function(err, r) {
  928. if(err) return reject(err);
  929. resolve(r);
  930. });
  931. });
  932. };
  933. var createIndex = function(self, name, fieldOrSpec, options, callback) {
  934. // Get the write concern options
  935. var finalOptions = writeConcern({}, self, options, { readPreference: ReadPreference.PRIMARY });
  936. // Ensure we have a callback
  937. if(finalOptions.writeConcern && typeof callback != 'function') {
  938. throw MongoError.create({message: "Cannot use a writeConcern without a provided callback", driver:true});
  939. }
  940. // Run only against primary
  941. options.readPreference = ReadPreference.PRIMARY;
  942. // Did the user destroy the topology
  943. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  944. // Attempt to run using createIndexes command
  945. createIndexUsingCreateIndexes(self, name, fieldOrSpec, options, function(err, result) {
  946. if(err == null) return handleCallback(callback, err, result);
  947. // 67 = 'CannotCreateIndex' (malformed index options)
  948. // 85 = 'IndexOptionsConflict' (index already exists with different options)
  949. // 11000 = 'DuplicateKey' (couldn't build unique index because of dupes)
  950. // 11600 = 'InterruptedAtShutdown' (interrupted at shutdown)
  951. // These errors mean that the server recognized `createIndex` as a command
  952. // and so we don't need to fallback to an insert.
  953. if(err.code === 67 || err.code == 11000 || err.code === 85 || err.code == 11600) {
  954. return handleCallback(callback, err, result);
  955. }
  956. // Create command
  957. var doc = createCreateIndexCommand(self, name, fieldOrSpec, options);
  958. // Set no key checking
  959. finalOptions.checkKeys = false;
  960. // Insert document
  961. self.s.topology.insert(f("%s.%s", self.s.databaseName, Db.SYSTEM_INDEX_COLLECTION), doc, finalOptions, function(err, result) {
  962. if(callback == null) return;
  963. if(err) return handleCallback(callback, err);
  964. if(result == null) return handleCallback(callback, null, null);
  965. if(result.result.writeErrors) return handleCallback(callback, MongoError.create(result.result.writeErrors[0]), null);
  966. handleCallback(callback, null, doc.name);
  967. });
  968. });
  969. }
  970. define.classMethod('createIndex', {callback: true, promise:true});
  971. /**
  972. * Ensures that an index exists, if it does not it creates it
  973. * @method
  974. * @deprecated since version 2.0
  975. * @param {string} name The index name
  976. * @param {(string|object)} fieldOrSpec Defines the index.
  977. * @param {object} [options=null] Optional settings.
  978. * @param {(number|string)} [options.w=null] The write concern.
  979. * @param {number} [options.wtimeout=null] The write concern timeout.
  980. * @param {boolean} [options.j=false] Specify a journal write concern.
  981. * @param {boolean} [options.unique=false] Creates an unique index.
  982. * @param {boolean} [options.sparse=false] Creates a sparse index.
  983. * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
  984. * @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
  985. * @param {number} [options.min=null] For geospatial indexes set the lower bound for the co-ordinates.
  986. * @param {number} [options.max=null] For geospatial indexes set the high bound for the co-ordinates.
  987. * @param {number} [options.v=null] Specify the format version of the indexes.
  988. * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
  989. * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
  990. * @param {Db~resultCallback} [callback] The command result callback
  991. * @return {Promise} returns Promise if no callback passed
  992. */
  993. Db.prototype.ensureIndex = function(name, fieldOrSpec, options, callback) {
  994. var self = this;
  995. if(typeof options == 'function') callback = options, options = {};
  996. options = options || {};
  997. // If we have a callback fallback
  998. if(typeof callback == 'function') return ensureIndex(self, name, fieldOrSpec, options, callback);
  999. // Return a promise
  1000. return new this.s.promiseLibrary(function(resolve, reject) {
  1001. ensureIndex(self, name, fieldOrSpec, options, function(err, r) {
  1002. if(err) return reject(err);
  1003. resolve(r);
  1004. });
  1005. });
  1006. };
  1007. var ensureIndex = function(self, name, fieldOrSpec, options, callback) {
  1008. // Get the write concern options
  1009. var finalOptions = writeConcern({}, self, options);
  1010. // Create command
  1011. var selector = createCreateIndexCommand(self, name, fieldOrSpec, options);
  1012. var index_name = selector.name;
  1013. // Did the user destroy the topology
  1014. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1015. // Merge primary readPreference
  1016. finalOptions.readPreference = ReadPreference.PRIMARY
  1017. // Check if the index already exists
  1018. self.indexInformation(name, finalOptions, function(err, indexInformation) {
  1019. if(err != null && err.code != 26) return handleCallback(callback, err, null);
  1020. // If the index does not exist, create it
  1021. if(indexInformation == null || !indexInformation[index_name]) {
  1022. self.createIndex(name, fieldOrSpec, options, callback);
  1023. } else {
  1024. if(typeof callback === 'function') return handleCallback(callback, null, index_name);
  1025. }
  1026. });
  1027. }
  1028. define.classMethod('ensureIndex', {callback: true, promise:true});
  1029. Db.prototype.addChild = function(db) {
  1030. if(this.s.parentDb) return this.s.parentDb.addChild(db);
  1031. this.s.children.push(db);
  1032. }
  1033. /**
  1034. * Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
  1035. * related in a parent-child relationship to the original instance so that events are correctly emitted on child
  1036. * db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
  1037. * You can control these behaviors with the options noListener and returnNonCachedInstance.
  1038. *
  1039. * @method
  1040. * @param {string} name The name of the database we want to use.
  1041. * @param {object} [options=null] Optional settings.
  1042. * @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
  1043. * @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
  1044. * @return {Db}
  1045. */
  1046. Db.prototype.db = function(dbName, options) {
  1047. options = options || {};
  1048. // Copy the options and add out internal override of the not shared flag
  1049. var finalOptions = assign({}, this.options, options);
  1050. // Do we have the db in the cache already
  1051. if(this.s.dbCache[dbName] && finalOptions.returnNonCachedInstance !== true) {
  1052. return this.s.dbCache[dbName];
  1053. }
  1054. // Add current db as parentDb
  1055. if(finalOptions.noListener == null || finalOptions.noListener == false) {
  1056. finalOptions.parentDb = this;
  1057. }
  1058. // Add promiseLibrary
  1059. finalOptions.promiseLibrary = this.s.promiseLibrary;
  1060. // Return the db object
  1061. var db = new Db(dbName, this.s.topology, finalOptions)
  1062. // Add as child
  1063. if(finalOptions.noListener == null || finalOptions.noListener == false) {
  1064. this.addChild(db);
  1065. }
  1066. // Add the db to the cache
  1067. this.s.dbCache[dbName] = db;
  1068. // Return the database
  1069. return db;
  1070. };
  1071. define.classMethod('db', {callback: false, promise:false, returns: [Db]});
  1072. var _executeAuthCreateUserCommand = function(self, username, password, options, callback) {
  1073. // Special case where there is no password ($external users)
  1074. if(typeof username == 'string'
  1075. && password != null && typeof password == 'object') {
  1076. options = password;
  1077. password = null;
  1078. }
  1079. // Unpack all options
  1080. if(typeof options == 'function') {
  1081. callback = options;
  1082. options = {};
  1083. }
  1084. // Error out if we digestPassword set
  1085. if(options.digestPassword != null) {
  1086. throw toError("The digestPassword option is not supported via add_user. Please use db.command('createUser', ...) instead for this option.");
  1087. }
  1088. // Get additional values
  1089. var customData = options.customData != null ? options.customData : {};
  1090. var roles = Array.isArray(options.roles) ? options.roles : [];
  1091. var maxTimeMS = typeof options.maxTimeMS == 'number' ? options.maxTimeMS : null;
  1092. // If not roles defined print deprecated message
  1093. if(roles.length == 0) {
  1094. console.log("Creating a user without roles is deprecated in MongoDB >= 2.6");
  1095. }
  1096. // Get the error options
  1097. var commandOptions = {writeCommand:true};
  1098. if(options['dbName']) commandOptions.dbName = options['dbName'];
  1099. // Add maxTimeMS to options if set
  1100. if(maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS;
  1101. // Check the db name and add roles if needed
  1102. if((self.databaseName.toLowerCase() == 'admin' || options.dbName == 'admin') && !Array.isArray(options.roles)) {
  1103. roles = ['root']
  1104. } else if(!Array.isArray(options.roles)) {
  1105. roles = ['dbOwner']
  1106. }
  1107. // Build the command to execute
  1108. var command = {
  1109. createUser: username
  1110. , customData: customData
  1111. , roles: roles
  1112. , digestPassword:false
  1113. }
  1114. // Apply write concern to command
  1115. command = writeConcern(command, self, options);
  1116. // Use node md5 generator
  1117. var md5 = crypto.createHash('md5');
  1118. // Generate keys used for authentication
  1119. md5.update(username + ":mongo:" + password);
  1120. var userPassword = md5.digest('hex');
  1121. // No password
  1122. if(typeof password == 'string') {
  1123. command.pwd = userPassword;
  1124. }
  1125. // Force write using primary
  1126. commandOptions.readPreference = ReadPreference.primary;
  1127. // Execute the command
  1128. self.command(command, commandOptions, function(err, result) {
  1129. if(err && err.ok == 0 && err.code == undefined) return handleCallback(callback, {code: -5000}, null);
  1130. if(err) return handleCallback(callback, err, null);
  1131. handleCallback(callback, !result.ok ? toError(result) : null
  1132. , result.ok ? [{user: username, pwd: ''}] : null);
  1133. })
  1134. }
  1135. var addUser = function(self, username, password, options, callback) {
  1136. // Did the user destroy the topology
  1137. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1138. // Attempt to execute auth command
  1139. _executeAuthCreateUserCommand(self, username, password, options, function(err, r) {
  1140. // We need to perform the backward compatible insert operation
  1141. if(err && err.code == -5000) {
  1142. var finalOptions = writeConcern(shallowClone(options), self, options);
  1143. // Use node md5 generator
  1144. var md5 = crypto.createHash('md5');
  1145. // Generate keys used for authentication
  1146. md5.update(username + ":mongo:" + password);
  1147. var userPassword = md5.digest('hex');
  1148. // If we have another db set
  1149. var db = options.dbName ? self.db(options.dbName) : self;
  1150. // Fetch a user collection
  1151. var collection = db.collection(Db.SYSTEM_USER_COLLECTION);
  1152. // Check if we are inserting the first user
  1153. collection.count({}, function(err, count) {
  1154. // We got an error (f.ex not authorized)
  1155. if(err != null) return handleCallback(callback, err, null);
  1156. // Check if the user exists and update i
  1157. collection.find({user: username}, {dbName: options['dbName']}).toArray(function(err) {
  1158. // We got an error (f.ex not authorized)
  1159. if(err != null) return handleCallback(callback, err, null);
  1160. // Add command keys
  1161. finalOptions.upsert = true;
  1162. // We have a user, let's update the password or upsert if not
  1163. collection.update({user: username},{$set: {user: username, pwd: userPassword}}, finalOptions, function(err) {
  1164. if(count == 0 && err) return handleCallback(callback, null, [{user:username, pwd:userPassword}]);
  1165. if(err) return handleCallback(callback, err, null)
  1166. handleCallback(callback, null, [{user:username, pwd:userPassword}]);
  1167. });
  1168. });
  1169. });
  1170. return;
  1171. }
  1172. if(err) return handleCallback(callback, err);
  1173. handleCallback(callback, err, r);
  1174. });
  1175. }
  1176. /**
  1177. * Add a user to the database.
  1178. * @method
  1179. * @param {string} username The username.
  1180. * @param {string} password The password.
  1181. * @param {object} [options=null] Optional settings.
  1182. * @param {(number|string)} [options.w=null] The write concern.
  1183. * @param {number} [options.wtimeout=null] The write concern timeout.
  1184. * @param {boolean} [options.j=false] Specify a journal write concern.
  1185. * @param {object} [options.customData=null] Custom data associated with the user (only Mongodb 2.6 or higher)
  1186. * @param {object[]} [options.roles=null] Roles associated with the created user (only Mongodb 2.6 or higher)
  1187. * @param {Db~resultCallback} [callback] The command result callback
  1188. * @return {Promise} returns Promise if no callback passed
  1189. */
  1190. Db.prototype.addUser = function(username, password, options, callback) {
  1191. // Unpack the parameters
  1192. var self = this;
  1193. var args = Array.prototype.slice.call(arguments, 2);
  1194. callback = args.pop();
  1195. if(typeof callback != 'function') args.push(callback);
  1196. options = args.length ? args.shift() || {} : {};
  1197. // If we have a callback fallback
  1198. if(typeof callback == 'function') return addUser(self, username, password, options, callback);
  1199. // Return a promise
  1200. return new this.s.promiseLibrary(function(resolve, reject) {
  1201. addUser(self, username, password, options, function(err, r) {
  1202. if(err) return reject(err);
  1203. resolve(r);
  1204. });
  1205. });
  1206. };
  1207. define.classMethod('addUser', {callback: true, promise:true});
  1208. var _executeAuthRemoveUserCommand = function(self, username, options, callback) {
  1209. if(typeof options == 'function') callback = options, options = {};
  1210. // Did the user destroy the topology
  1211. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1212. // Get the error options
  1213. var commandOptions = {writeCommand:true};
  1214. if(options['dbName']) commandOptions.dbName = options['dbName'];
  1215. // Get additional values
  1216. var maxTimeMS = typeof options.maxTimeMS == 'number' ? options.maxTimeMS : null;
  1217. // Add maxTimeMS to options if set
  1218. if(maxTimeMS != null) commandOptions.maxTimeMS = maxTimeMS;
  1219. // Build the command to execute
  1220. var command = {
  1221. dropUser: username
  1222. }
  1223. // Apply write concern to command
  1224. command = writeConcern(command, self, options);
  1225. // Force write using primary
  1226. commandOptions.readPreference = ReadPreference.primary;
  1227. // Execute the command
  1228. self.command(command, commandOptions, function(err, result) {
  1229. if(err && !err.ok && err.code == undefined) return handleCallback(callback, {code: -5000});
  1230. if(err) return handleCallback(callback, err, null);
  1231. handleCallback(callback, null, result.ok ? true : false);
  1232. })
  1233. }
  1234. var removeUser = function(self, username, options, callback) {
  1235. // Attempt to execute command
  1236. _executeAuthRemoveUserCommand(self, username, options, function(err, result) {
  1237. if(err && err.code == -5000) {
  1238. var finalOptions = writeConcern(shallowClone(options), self, options);
  1239. // If we have another db set
  1240. var db = options.dbName ? self.db(options.dbName) : self;
  1241. // Fetch a user collection
  1242. var collection = db.collection(Db.SYSTEM_USER_COLLECTION);
  1243. // Locate the user
  1244. collection.findOne({user: username}, {}, function(err, user) {
  1245. if(user == null) return handleCallback(callback, err, false);
  1246. collection.remove({user: username}, finalOptions, function(err) {
  1247. handleCallback(callback, err, true);
  1248. });
  1249. });
  1250. return;
  1251. }
  1252. if(err) return handleCallback(callback, err);
  1253. handleCallback(callback, err, result);
  1254. });
  1255. }
  1256. define.classMethod('removeUser', {callback: true, promise:true});
  1257. /**
  1258. * Remove a user from a database
  1259. * @method
  1260. * @param {string} username The username.
  1261. * @param {object} [options=null] Optional settings.
  1262. * @param {(number|string)} [options.w=null] The write concern.
  1263. * @param {number} [options.wtimeout=null] The write concern timeout.
  1264. * @param {boolean} [options.j=false] Specify a journal write concern.
  1265. * @param {Db~resultCallback} [callback] The command result callback
  1266. * @return {Promise} returns Promise if no callback passed
  1267. */
  1268. Db.prototype.removeUser = function(username, options, callback) {
  1269. // Unpack the parameters
  1270. var self = this;
  1271. var args = Array.prototype.slice.call(arguments, 1);
  1272. callback = args.pop();
  1273. if(typeof callback != 'function') args.push(callback);
  1274. options = args.length ? args.shift() || {} : {};
  1275. // If we have a callback fallback
  1276. if(typeof callback == 'function') return removeUser(self, username, options, callback);
  1277. // Return a promise
  1278. return new this.s.promiseLibrary(function(resolve, reject) {
  1279. removeUser(self, username, options, function(err, r) {
  1280. if(err) return reject(err);
  1281. resolve(r);
  1282. });
  1283. });
  1284. };
  1285. /**
  1286. * Authenticate a user against the server.
  1287. * @method
  1288. * @param {string} username The username.
  1289. * @param {string} [password] The password.
  1290. * @param {object} [options=null] Optional settings.
  1291. * @param {string} [options.authMechanism=MONGODB-CR] The authentication mechanism to use, GSSAPI, MONGODB-CR, MONGODB-X509, PLAIN
  1292. * @param {Db~resultCallback} [callback] The command result callback
  1293. * @return {Promise} returns Promise if no callback passed
  1294. * @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.
  1295. */
  1296. Db.prototype.authenticate = function(username, password, options, callback) {
  1297. 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.");
  1298. return authenticate.apply(this, [this].concat(Array.prototype.slice.call(arguments)));
  1299. };
  1300. define.classMethod('authenticate', {callback: true, promise:true});
  1301. /**
  1302. * Logout user from server, fire off on all connections and remove all auth info
  1303. * @method
  1304. * @param {object} [options=null] Optional settings.
  1305. * @param {string} [options.dbName=null] Logout against different database than current.
  1306. * @param {Db~resultCallback} [callback] The command result callback
  1307. * @return {Promise} returns Promise if no callback passed
  1308. */
  1309. Db.prototype.logout = function(options, callback) {
  1310. var self = this;
  1311. if(typeof options == 'function') callback = options, options = {};
  1312. options = options || {};
  1313. // Establish the correct database name
  1314. var dbName = this.s.authSource ? this.s.authSource : this.s.databaseName;
  1315. dbName = options.dbName ? options.dbName : dbName;
  1316. // If we have a callback
  1317. if(typeof callback == 'function') {
  1318. return self.s.topology.logout(dbName, function(err) {
  1319. if(err) return callback(err);
  1320. callback(null, true);
  1321. });
  1322. }
  1323. // Return a promise
  1324. return new this.s.promiseLibrary(function(resolve, reject) {
  1325. self.s.topology.logout(dbName, function(err) {
  1326. if(err) return reject(err);
  1327. resolve(true);
  1328. });
  1329. });
  1330. }
  1331. define.classMethod('logout', {callback: true, promise:true});
  1332. /**
  1333. * Retrieves this collections index info.
  1334. * @method
  1335. * @param {string} name The name of the collection.
  1336. * @param {object} [options=null] Optional settings.
  1337. * @param {boolean} [options.full=false] Returns the full raw index information.
  1338. * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
  1339. * @param {Db~resultCallback} [callback] The command result callback
  1340. * @return {Promise} returns Promise if no callback passed
  1341. */
  1342. Db.prototype.indexInformation = function(name, options, callback) {
  1343. var self = this;
  1344. if(typeof options == 'function') callback = options, options = {};
  1345. options = options || {};
  1346. // If we have a callback fallback
  1347. if(typeof callback == 'function') return indexInformation(self, name, options, callback);
  1348. // Return a promise
  1349. return new this.s.promiseLibrary(function(resolve, reject) {
  1350. indexInformation(self, name, options, function(err, r) {
  1351. if(err) return reject(err);
  1352. resolve(r);
  1353. });
  1354. });
  1355. };
  1356. var indexInformation = function(self, name, options, callback) {
  1357. // If we specified full information
  1358. var full = options['full'] == null ? false : options['full'];
  1359. // Did the user destroy the topology
  1360. if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
  1361. // Process all the results from the index command and collection
  1362. var processResults = function(indexes) {
  1363. // Contains all the information
  1364. var info = {};
  1365. // Process all the indexes
  1366. for(var i = 0; i < indexes.length; i++) {
  1367. var index = indexes[i];
  1368. // Let's unpack the object
  1369. info[index.name] = [];
  1370. for(var name in index.key) {
  1371. info[index.name].push([name, index.key[name]]);
  1372. }
  1373. }
  1374. return info;
  1375. }
  1376. // Get the list of indexes of the specified collection
  1377. self.collection(name).listIndexes(options).toArray(function(err, indexes) {
  1378. if(err) return callback(toError(err));
  1379. if(!Array.isArray(indexes)) return handleCallback(callback, null, []);
  1380. if(full) return handleCallback(callback, null, indexes);
  1381. handleCallback(callback, null, processResults(indexes));
  1382. });
  1383. }
  1384. define.classMethod('indexInformation', {callback: true, promise:true});
  1385. var createCreateIndexCommand = function(db, name, fieldOrSpec, options) {
  1386. var indexParameters = parseIndexOptions(fieldOrSpec);
  1387. var fieldHash = indexParameters.fieldHash;
  1388. // Generate the index name
  1389. var indexName = typeof options.name == 'string' ? options.name : indexParameters.name;
  1390. var selector = {
  1391. 'ns': db.databaseName + "." + name, 'key': fieldHash, 'name': indexName
  1392. }
  1393. // Ensure we have a correct finalUnique
  1394. var finalUnique = options == null || 'object' === typeof options ? false : options;
  1395. // Set up options
  1396. options = options == null || typeof options == 'boolean' ? {} : options;
  1397. // Add all the options
  1398. var keysToOmit = Object.keys(selector);
  1399. for(var optionName in options) {
  1400. if(keysToOmit.indexOf(optionName) == -1) {
  1401. selector[optionName] = options[optionName];
  1402. }
  1403. }
  1404. if(selector['unique'] == null) selector['unique'] = finalUnique;
  1405. // Remove any write concern operations
  1406. var removeKeys = ['w', 'wtimeout', 'j', 'fsync', 'readPreference'];
  1407. for(var i = 0; i < removeKeys.length; i++) {
  1408. delete selector[removeKeys[i]];
  1409. }
  1410. // Return the command creation selector
  1411. return selector;
  1412. }
  1413. var createIndexUsingCreateIndexes = function(self, name, fieldOrSpec, options, callback) {
  1414. // Build the index
  1415. var indexParameters = parseIndexOptions(fieldOrSpec);
  1416. // Generate the index name
  1417. var indexName = typeof options.name == 'string' ? options.name : indexParameters.name;
  1418. // Set up the index
  1419. var indexes = [{ name: indexName, key: indexParameters.fieldHash }];
  1420. // merge all the options
  1421. var keysToOmit = Object.keys(indexes[0]);
  1422. for(var optionName in options) {
  1423. if(keysToOmit.indexOf(optionName) == -1) {
  1424. indexes[0][optionName] = options[optionName];
  1425. }
  1426. // Remove any write concern operations
  1427. var removeKeys = ['w', 'wtimeout', 'j', 'fsync', 'readPreference'];
  1428. for(var i = 0; i < removeKeys.length; i++) {
  1429. delete indexes[0][removeKeys[i]];
  1430. }
  1431. }
  1432. // Get capabilities
  1433. var capabilities = self.s.topology.capabilities();
  1434. // Did the user pass in a collation, check if our write server supports it
  1435. if(indexes[0].collation && capabilities && !capabilities.commandsTakeCollation) {
  1436. // Create a new error
  1437. var error = new MongoError(f('server/primary/mongos does not support collation'));
  1438. error.code = 67;
  1439. // Return the error
  1440. return callback(error);
  1441. }
  1442. // Create command, apply write concern to command
  1443. var cmd = writeConcern({createIndexes: name, indexes: indexes}, self, options);
  1444. // Decorate command with writeConcern if supported
  1445. decorateWithWriteConcern(cmd, self, options);
  1446. // ReadPreference primary
  1447. options.readPreference = ReadPreference.PRIMARY;
  1448. // Build the command
  1449. self.command(cmd, options, function(err, result) {
  1450. if(err) return handleCallback(callback, err, null);
  1451. if(result.ok == 0) return handleCallback(callback, toError(result), null);
  1452. // Return the indexName for backward compatibility
  1453. handleCallback(callback, null, indexName);
  1454. });
  1455. }
  1456. // Validate the database name
  1457. var validateDatabaseName = function(databaseName) {
  1458. if(typeof databaseName !== 'string') throw MongoError.create({message: "database name must be a string", driver:true});
  1459. if(databaseName.length === 0) throw MongoError.create({message: "database name cannot be the empty string", driver:true});
  1460. if(databaseName == '$external') return;
  1461. var invalidChars = [" ", ".", "$", "/", "\\"];
  1462. for(var i = 0; i < invalidChars.length; i++) {
  1463. if(databaseName.indexOf(invalidChars[i]) != -1) throw MongoError.create({message: "database names cannot contain the character '" + invalidChars[i] + "'", driver:true});
  1464. }
  1465. }
  1466. // Get write concern
  1467. var writeConcern = function(target, db, options) {
  1468. if(options.w != null || options.j != null || options.fsync != null) {
  1469. var opts = {};
  1470. if(options.w) opts.w = options.w;
  1471. if(options.wtimeout) opts.wtimeout = options.wtimeout;
  1472. if(options.j) opts.j = options.j;
  1473. if(options.fsync) opts.fsync = options.fsync;
  1474. target.writeConcern = opts;
  1475. } else if(db.writeConcern.w != null || db.writeConcern.j != null || db.writeConcern.fsync != null) {
  1476. target.writeConcern = db.writeConcern;
  1477. }
  1478. return target
  1479. }
  1480. // Add listeners to topology
  1481. var createListener = function(self, e, object) {
  1482. var listener = function(err) {
  1483. if(object.listeners(e).length > 0) {
  1484. object.emit(e, err, self);
  1485. // Emit on all associated db's if available
  1486. for(var i = 0; i < self.s.children.length; i++) {
  1487. self.s.children[i].emit(e, err, self.s.children[i]);
  1488. }
  1489. }
  1490. }
  1491. return listener;
  1492. }
  1493. /**
  1494. * Unref all sockets
  1495. * @method
  1496. */
  1497. Db.prototype.unref = function() {
  1498. this.s.topology.unref();
  1499. }
  1500. /**
  1501. * Db close event
  1502. *
  1503. * Emitted after a socket closed against a single server or mongos proxy.
  1504. *
  1505. * @event Db#close
  1506. * @type {MongoError}
  1507. */
  1508. /**
  1509. * Db authenticated event
  1510. *
  1511. * Emitted after all server members in the topology (single server, replicaset or mongos) have successfully authenticated.
  1512. *
  1513. * @event Db#authenticated
  1514. * @type {object}
  1515. */
  1516. /**
  1517. * Db reconnect event
  1518. *
  1519. * * Server: Emitted when the driver has reconnected and re-authenticated.
  1520. * * ReplicaSet: N/A
  1521. * * Mongos: Emitted when the driver reconnects and re-authenticates successfully against a Mongos.
  1522. *
  1523. * @event Db#reconnect
  1524. * @type {object}
  1525. */
  1526. /**
  1527. * Db error event
  1528. *
  1529. * Emitted after an error occurred against a single server or mongos proxy.
  1530. *
  1531. * @event Db#error
  1532. * @type {MongoError}
  1533. */
  1534. /**
  1535. * Db timeout event
  1536. *
  1537. * Emitted after a socket timeout occurred against a single server or mongos proxy.
  1538. *
  1539. * @event Db#timeout
  1540. * @type {MongoError}
  1541. */
  1542. /**
  1543. * Db parseError event
  1544. *
  1545. * The parseError event is emitted if the driver detects illegal or corrupt BSON being received from the server.
  1546. *
  1547. * @event Db#parseError
  1548. * @type {MongoError}
  1549. */
  1550. /**
  1551. * Db fullsetup event, emitted when all servers in the topology have been connected to at start up time.
  1552. *
  1553. * * Server: Emitted when the driver has connected to the single server and has authenticated.
  1554. * * ReplSet: Emitted after the driver has attempted to connect to all replicaset members.
  1555. * * Mongos: Emitted after the driver has attempted to connect to all mongos proxies.
  1556. *
  1557. * @event Db#fullsetup
  1558. * @type {Db}
  1559. */
  1560. // Constants
  1561. Db.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces";
  1562. Db.SYSTEM_INDEX_COLLECTION = "system.indexes";
  1563. Db.SYSTEM_PROFILE_COLLECTION = "system.profile";
  1564. Db.SYSTEM_USER_COLLECTION = "system.users";
  1565. Db.SYSTEM_COMMAND_COLLECTION = "$cmd";
  1566. Db.SYSTEM_JS_COLLECTION = "system.js";
  1567. module.exports = Db;