db.js 66 KB

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