mongodb 2.1.0-alpha → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/HISTORY.md +574 -429
  2. package/Makefile +2 -5
  3. package/README.md +108 -15
  4. package/conf.json +17 -13
  5. package/index.js +13 -2
  6. package/lib/admin.js +113 -47
  7. package/lib/aggregation_cursor.js +56 -28
  8. package/lib/apm.js +608 -0
  9. package/lib/bulk/common.js +7 -7
  10. package/lib/bulk/ordered.js +56 -17
  11. package/lib/bulk/unordered.js +52 -14
  12. package/lib/collection.js +671 -212
  13. package/lib/command_cursor.js +60 -32
  14. package/lib/cursor.js +313 -115
  15. package/lib/db.js +264 -105
  16. package/lib/gridfs/chunk.js +26 -29
  17. package/lib/gridfs/grid_store.js +150 -64
  18. package/lib/gridfs-stream/download.js +310 -0
  19. package/lib/gridfs-stream/index.js +335 -0
  20. package/lib/gridfs-stream/upload.js +450 -0
  21. package/lib/metadata.js +64 -0
  22. package/lib/mongo_client.js +69 -39
  23. package/lib/mongos.js +65 -20
  24. package/lib/replset.js +69 -34
  25. package/lib/server.js +35 -1
  26. package/lib/topology_base.js +22 -10
  27. package/lib/url_parser.js +111 -13
  28. package/lib/utils.js +9 -8
  29. package/mongolabs.js +427 -0
  30. package/package.json +8 -6
  31. package/t.js +68 -51
  32. package/test.js +12 -0
  33. package/test_boot/boot.sh +3 -0
  34. package/test_boot/ca.pem +49 -0
  35. package/test_boot/client.pem +48 -0
  36. package/test_boot/client_password.pem +51 -0
  37. package/test_boot/connect.js +29 -0
  38. package/test_boot/data/WiredTiger +2 -0
  39. package/test_boot/data/WiredTiger.lock +1 -0
  40. package/test_boot/data/WiredTiger.turtle +6 -0
  41. package/test_boot/data/WiredTiger.wt +0 -0
  42. package/test_boot/data/WiredTigerLAS.wt +0 -0
  43. package/test_boot/data/_mdb_catalog.wt +0 -0
  44. package/test_boot/data/collection-0-757073248613337118.wt +0 -0
  45. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-44-37Z-00000 +0 -0
  46. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-45-15Z-00000 +0 -0
  47. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-46-31Z-00000 +0 -0
  48. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-47-25Z-00000 +0 -0
  49. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-49-07Z-00000 +0 -0
  50. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-41Z-00000 +0 -0
  51. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-50-53Z-00000 +0 -0
  52. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-52-31Z-00000 +0 -0
  53. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-54-53Z-00000 +0 -0
  54. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-09Z-00000 +0 -0
  55. package/test_boot/data/diagnostic.data/metrics.2015-10-07T14-55-38Z-00000 +0 -0
  56. package/test_boot/data/index-1-757073248613337118.wt +0 -0
  57. package/test_boot/data/mongod.lock +0 -0
  58. package/test_boot/data/sizeStorer.wt +0 -0
  59. package/test_boot/data/storage.bson +0 -0
  60. package/test_boot/server_password.pem +51 -0
  61. package/.travis.yml +0 -10
  62. package/t1.js +0 -59
  63. package/wercker.yml +0 -19
package/lib/collection.js CHANGED
@@ -17,6 +17,7 @@ var checkCollectionName = require('./utils').checkCollectionName
17
17
  , ReadPreference = require('./read_preference')
18
18
  , CoreReadPreference = require('mongodb-core').ReadPreference
19
19
  , CommandCursor = require('./command_cursor')
20
+ , Define = require('./metadata')
20
21
  , Cursor = require('./cursor')
21
22
  , unordered = require('./bulk/unordered')
22
23
  , ordered = require('./bulk/ordered');
@@ -24,7 +25,7 @@ var checkCollectionName = require('./utils').checkCollectionName
24
25
  /**
25
26
  * @fileOverview The **Collection** class is an internal class that embodies a MongoDB collection
26
27
  * allowing for insert/update/remove/find and other command operation on that MongoDB collection.
27
- *
28
+ *
28
29
  * **COLLECTION Cannot directly be instantiated**
29
30
  * @example
30
31
  * var MongoClient = require('mongodb').MongoClient,
@@ -50,10 +51,11 @@ var checkCollectionName = require('./utils').checkCollectionName
50
51
  * @property {string} collectionName Get the collection name.
51
52
  * @property {string} namespace Get the full collection namespace.
52
53
  * @property {object} writeConcern The current write concern values.
54
+ * @property {object} readConcern The current read concern values.
53
55
  * @property {object} hint Get current index hint for collection.
54
56
  * @return {Collection} a Collection instance.
55
57
  */
56
- var Collection = function(db, topology, dbName, name, pkFactory, options) {
58
+ var Collection = function(db, topology, dbName, name, pkFactory, options) {
57
59
  checkCollectionName(name);
58
60
  var self = this;
59
61
  // Unpack variables
@@ -117,9 +119,13 @@ var Collection = function(db, topology, dbName, name, pkFactory, options) {
117
119
  , name: name
118
120
  // Promise library
119
121
  , promiseLibrary: promiseLibrary
122
+ // Read Concern
123
+ , readConcern: options.readConcern
120
124
  }
121
125
  }
122
126
 
127
+ var define = Collection.define = new Define('Collection', Collection, false);
128
+
123
129
  Object.defineProperty(Collection.prototype, 'collectionName', {
124
130
  enumerable: true, get: function() { return this.s.name; }
125
131
  });
@@ -128,9 +134,13 @@ Object.defineProperty(Collection.prototype, 'namespace', {
128
134
  enumerable: true, get: function() { return this.s.namespace; }
129
135
  });
130
136
 
137
+ Object.defineProperty(Collection.prototype, 'readConcern', {
138
+ enumerable: true, get: function() { return this.s.readConcern || {level: 'local'}; }
139
+ });
140
+
131
141
  Object.defineProperty(Collection.prototype, 'writeConcern', {
132
142
  enumerable:true,
133
- get: function() {
143
+ get: function() {
134
144
  var ops = {};
135
145
  if(this.s.options.w != null) ops.w = this.s.options.w;
136
146
  if(this.s.options.j != null) ops.j = this.s.options.j;
@@ -172,7 +182,7 @@ Collection.prototype.find = function() {
172
182
  options = args[0];
173
183
  }
174
184
 
175
- if(len === 2 && !Array.isArray(fields)) {
185
+ if(len === 2 && fields !== undefined && !Array.isArray(fields)) {
176
186
  var fieldKeys = Object.keys(fields);
177
187
  var is_option = false;
178
188
 
@@ -277,7 +287,7 @@ Collection.prototype.find = function() {
277
287
 
278
288
  // Ensure the query is an object
279
289
  if(selector != null && typeof selector != 'object') {
280
- throw new MongoError("query selector must be an object");
290
+ throw MongoError.create({message: "query selector must be an object", driver:true });
281
291
  }
282
292
 
283
293
  // Build the find command
@@ -292,7 +302,7 @@ Collection.prototype.find = function() {
292
302
  if(typeof newOptions.awaitdata == 'boolean') {
293
303
  newOptions.awaitData = newOptions.awaitdata
294
304
  };
295
-
305
+
296
306
  // Translate to new command option noCursorTimeout
297
307
  if(typeof newOptions.timeout == 'boolean') newOptions.noCursorTimeout = newOptions.timeout;
298
308
 
@@ -332,16 +342,26 @@ Collection.prototype.find = function() {
332
342
  if(newOptions.raw == null && this.s.raw) newOptions.raw = this.s.raw;
333
343
 
334
344
  // Sort options
335
- if(findCommand.sort)
345
+ if(findCommand.sort)
336
346
  findCommand.sort = formattedOrderClause(findCommand.sort);
337
347
 
348
+ // Set the readConcern
349
+ if(this.s.readConcern) {
350
+ findCommand.readConcern = this.s.readConcern;
351
+ }
352
+
338
353
  // Create the cursor
339
354
  if(typeof callback == 'function') return handleCallback(callback, null, this.s.topology.cursor(this.s.namespace, findCommand, newOptions));
340
355
  return this.s.topology.cursor(this.s.namespace, findCommand, newOptions);
341
356
  }
342
357
 
358
+ define.classMethod('find', {callback: false, promise:false, returns: [Cursor]});
359
+
343
360
  /**
344
- * Inserts a single document into MongoDB.
361
+ * Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,
362
+ * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
363
+ * can be overridden by setting the **forceServerObjectId** flag.
364
+ *
345
365
  * @method
346
366
  * @param {object} doc Document to insert.
347
367
  * @param {object} [options=null] Optional settings.
@@ -350,13 +370,21 @@ Collection.prototype.find = function() {
350
370
  * @param {boolean} [options.j=false] Specify a journal write concern.
351
371
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
352
372
  * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
353
- * @param {Collection~writeOpCallback} callback The command result callback
373
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
374
+ * @param {Collection~insertOneWriteOpCallback} [callback] The command result callback
354
375
  * @return {Promise} returns Promise if no callback passed
355
376
  */
356
377
  Collection.prototype.insertOne = function(doc, options, callback) {
357
378
  var self = this;
358
379
  if(typeof options == 'function') callback = options, options = {};
359
- if(Array.isArray(doc)) return callback(new MongoError('doc parameter must be an object'));
380
+ options = options || {};
381
+ if(Array.isArray(doc)) return callback(MongoError.create({message: 'doc parameter must be an object', driver:true }));
382
+
383
+ // Add ignoreUndfined
384
+ if(this.s.options.ignoreUndefined) {
385
+ options = shallowClone(options);
386
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
387
+ }
360
388
 
361
389
  // Execute using callback
362
390
  if(typeof callback == 'function') return insertOne(self, doc, options, callback);
@@ -365,7 +393,7 @@ Collection.prototype.insertOne = function(doc, options, callback) {
365
393
  return new this.s.promiseLibrary(function(resolve, reject) {
366
394
  insertOne(self, doc, options, function(err, r) {
367
395
  if(err) return reject(err);
368
- resolve(r);
396
+ resolve(r);
369
397
  });
370
398
  });
371
399
  }
@@ -380,11 +408,35 @@ var insertOne = function(self, doc, options, callback) {
380
408
  r.insertedCount = r.result.n;
381
409
  r.insertedId = doc._id;
382
410
  if(callback) callback(null, r);
383
- });
411
+ });
384
412
  }
385
413
 
414
+ var mapInserManyResults = function(docs, r) {
415
+ var ids = r.getInsertedIds();
416
+ var keys = Object.keys(ids);
417
+ var finalIds = new Array(keys);
418
+
419
+ for(var i = 0; i < keys.length; i++) {
420
+ if(ids[keys[i]]._id) {
421
+ finalIds[ids[keys[i]].index] = ids[keys[i]]._id;
422
+ }
423
+ }
424
+
425
+ return {
426
+ result: {ok: 1, n: r.insertedCount},
427
+ ops: docs,
428
+ insertedCount: r.insertedCount,
429
+ insertedIds: finalIds
430
+ }
431
+ }
432
+
433
+ define.classMethod('insertOne', {callback: true, promise:true});
434
+
386
435
  /**
387
- * Inserts an array of documents into MongoDB.
436
+ * Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
437
+ * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
438
+ * can be overridden by setting the **forceServerObjectId** flag.
439
+ *
388
440
  * @method
389
441
  * @param {object[]} docs Documents to insert.
390
442
  * @param {object} [options=null] Optional settings.
@@ -393,40 +445,56 @@ var insertOne = function(self, doc, options, callback) {
393
445
  * @param {boolean} [options.j=false] Specify a journal write concern.
394
446
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
395
447
  * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
396
- * @param {Collection~writeOpCallback} callback The command result callback
448
+ * @param {Collection~insertWriteOpCallback} [callback] The command result callback
397
449
  * @return {Promise} returns Promise if no callback passed
398
450
  */
399
451
  Collection.prototype.insertMany = function(docs, options, callback) {
400
452
  var self = this;
401
453
  if(typeof options == 'function') callback = options, options = {};
402
- if(!Array.isArray(docs)) return callback(new MongoError('docs parameter must be an array of documents'));
454
+ options = options || {ordered:true};
455
+ if(!Array.isArray(docs)) return callback(MongoError.create({message: 'docs parameter must be an array of documents', driver:true }));
456
+
457
+ // Get the write concern options
458
+ if(typeof options.checkKeys != 'boolean') {
459
+ options.checkKeys = true;
460
+ }
461
+
462
+ // If keep going set unordered
463
+ options['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
464
+
465
+ // Set up the force server object id
466
+ var forceServerObjectId = typeof options.forceServerObjectId == 'boolean'
467
+ ? options.forceServerObjectId : self.s.db.options.forceServerObjectId;
468
+
469
+ // Do we want to force the server to assign the _id key
470
+ if(forceServerObjectId !== true) {
471
+ // Add _id if not specified
472
+ for(var i = 0; i < docs.length; i++) {
473
+ if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
474
+ }
475
+ }
476
+
477
+ // Generate the bulk write operations
478
+ var operations = [{
479
+ insertMany: docs
480
+ }];
403
481
 
404
482
  // Execute using callback
405
- if(typeof callback == 'function') return insertMany(self, docs, options, callback);
483
+ if(typeof callback == 'function') return bulkWrite(self, operations, options, function(err, r) {
484
+ if(err) return callback(err, r);
485
+ callback(null, mapInserManyResults(docs, r));
486
+ });
406
487
 
407
488
  // Return a Promise
408
489
  return new this.s.promiseLibrary(function(resolve, reject) {
409
- insertMany(self, docs, options, function(err, r) {
490
+ bulkWrite(self, operations, options, function(err, r) {
410
491
  if(err) return reject(err);
411
- resolve(r);
492
+ resolve(mapInserManyResults(docs, r));
412
493
  });
413
494
  });
414
495
  }
415
496
 
416
- var insertMany = function(self, docs, options, callback) {
417
- insertDocuments(self, docs, options, function(err, r) {
418
- if(callback == null) return;
419
- if(err && callback) return callback(err);
420
- if(r == null) return callback(null, {result: {ok:1}});
421
- r.insertedCount = r.result.n;
422
- var ids = [];
423
- for(var i = 0; i < docs.length; i++) {
424
- if(docs[i]._id) ids.push(docs[i]._id);
425
- }
426
- r.insertedIds = ids;
427
- if(callback) callback(null, r);
428
- });
429
- }
497
+ define.classMethod('insertMany', {callback: true, promise:true});
430
498
 
431
499
  /**
432
500
  * @typedef {Object} Collection~BulkWriteOpResult
@@ -464,6 +532,10 @@ var insertMany = function(self, docs, options, callback) {
464
532
  *
465
533
  * { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}
466
534
  *
535
+ * If documents passed in do not contain the **_id** field,
536
+ * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
537
+ * can be overridden by setting the **forceServerObjectId** flag.
538
+ *
467
539
  * @method
468
540
  * @param {object[]} operations Bulk operations to perform.
469
541
  * @param {object} [options=null] Optional settings.
@@ -471,13 +543,19 @@ var insertMany = function(self, docs, options, callback) {
471
543
  * @param {number} [options.wtimeout=null] The write concern timeout.
472
544
  * @param {boolean} [options.j=false] Specify a journal write concern.
473
545
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
474
- * @param {Collection~bulkWriteOpCallback} callback The command result callback
546
+ * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
547
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
548
+ * @param {Collection~bulkWriteOpCallback} [callback] The command result callback
475
549
  * @return {Promise} returns Promise if no callback passed
476
550
  */
477
551
  Collection.prototype.bulkWrite = function(operations, options, callback) {
478
552
  var self = this;
479
553
  if(typeof options == 'function') callback = options, options = {};
480
- if(!Array.isArray(operations)) throw new MongoError("operations must be an array of documents");
554
+ options = options || {ordered:true};
555
+
556
+ if(!Array.isArray(operations)) {
557
+ throw MongoError.create({message: "operations must be an array of documents", driver:true });
558
+ }
481
559
 
482
560
  // Execute using callback
483
561
  if(typeof callback == 'function') return bulkWrite(self, operations, options, callback);
@@ -486,14 +564,21 @@ Collection.prototype.bulkWrite = function(operations, options, callback) {
486
564
  return new this.s.promiseLibrary(function(resolve, reject) {
487
565
  bulkWrite(self, operations, options, function(err, r) {
488
566
  if(err) return reject(err);
489
- resolve(r);
567
+ resolve(r);
490
568
  });
491
569
  });
492
570
  }
493
571
 
494
572
  var bulkWrite = function(self, operations, options, callback) {
495
- var bulk = options.ordered == true || options.ordered == null ? self.initializeOrderedBulkOp() : self.initializeUnorderedBulkOp();
496
-
573
+ // Add ignoreUndfined
574
+ if(self.s.options.ignoreUndefined) {
575
+ options = shallowClone(options);
576
+ options.ignoreUndefined = self.s.options.ignoreUndefined;
577
+ }
578
+
579
+ // Create the bulk operation
580
+ var bulk = options.ordered == true || options.ordered == null ? self.initializeOrderedBulkOp(options) : self.initializeUnorderedBulkOp(options);
581
+
497
582
  // for each op go through and add to the bulk
498
583
  for(var i = 0; i < operations.length; i++) {
499
584
  bulk.raw(operations[i]);
@@ -505,6 +590,14 @@ var bulkWrite = function(self, operations, options, callback) {
505
590
 
506
591
  // Execute the bulk
507
592
  bulk.execute(writeCon, function(err, r) {
593
+ // We have connection level error
594
+ if(!r && err) return callback(err, null);
595
+ // We have single error
596
+ if(r && r.hasWriteErrors() && r.getWriteErrorCount() == 1) {
597
+ return callback(toError(r.getWriteErrorAt(0)), r);
598
+ }
599
+
600
+ // if(err) return callback(err);
508
601
  r.insertedCount = r.nInserted;
509
602
  r.matchedCount = r.nMatched;
510
603
  r.modifiedCount = r.nModified || 0;
@@ -513,6 +606,9 @@ var bulkWrite = function(self, operations, options, callback) {
513
606
  r.upsertedIds = {};
514
607
  r.insertedIds = {};
515
608
 
609
+ // Update the n
610
+ r.n = r.insertedCount;
611
+
516
612
  // Inserted documents
517
613
  var inserted = r.getInsertedIds();
518
614
  // Map inserted ids
@@ -525,7 +621,23 @@ var bulkWrite = function(self, operations, options, callback) {
525
621
  // Map upserted ids
526
622
  for(var i = 0; i < upserted.length; i++) {
527
623
  r.upsertedIds[upserted[i].index] = upserted[i]._id;
528
- }
624
+ }
625
+
626
+ // Check if we have write errors
627
+ if(r.hasWriteErrors()) {
628
+ // Get all the errors
629
+ var errors = r.getWriteErrors();
630
+ // Return the MongoError object
631
+ return callback(toError({
632
+ message: 'write operation failed', code: errors[0].code, writeErrors: errors
633
+ }), r);
634
+ }
635
+
636
+ // Check if we have a writeConcern error
637
+ if(r.getWriteConcernError()) {
638
+ // Return the MongoError object
639
+ return callback(toError(r.getWriteConcernError()), r);
640
+ }
529
641
 
530
642
  // Return the results
531
643
  callback(null, r);
@@ -546,9 +658,15 @@ var insertDocuments = function(self, docs, options, callback) {
546
658
  if(finalOptions.keepGoing == true) finalOptions.ordered = false;
547
659
  finalOptions['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
548
660
 
661
+ // Set up the force server object id
662
+ var forceServerObjectId = typeof options.forceServerObjectId == 'boolean'
663
+ ? options.forceServerObjectId : self.s.db.options.forceServerObjectId;
664
+
549
665
  // Add _id if not specified
550
- for(var i = 0; i < docs.length; i++) {
551
- if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
666
+ if(forceServerObjectId !== true){
667
+ for(var i = 0; i < docs.length; i++) {
668
+ if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
669
+ }
552
670
  }
553
671
 
554
672
  // File inserts
@@ -561,10 +679,12 @@ var insertDocuments = function(self, docs, options, callback) {
561
679
  // Add docs to the list
562
680
  result.ops = docs;
563
681
  // Return the results
564
- handleCallback(callback, null, result);
565
- });
682
+ handleCallback(callback, null, result);
683
+ });
566
684
  }
567
685
 
686
+ define.classMethod('bulkWrite', {callback: true, promise:true});
687
+
568
688
  /**
569
689
  * @typedef {Object} Collection~WriteOpResult
570
690
  * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
@@ -580,7 +700,46 @@ var insertDocuments = function(self, docs, options, callback) {
580
700
  */
581
701
 
582
702
  /**
583
- * Inserts a single document or a an array of documents into MongoDB.
703
+ * @typedef {Object} Collection~insertWriteOpResult
704
+ * @property {Number} insertedCount The total amount of documents inserted.
705
+ * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
706
+ * @property {ObjectId[]} insertedIds All the generated _id's for the inserted documents.
707
+ * @property {object} connection The connection object used for the operation.
708
+ * @property {object} result The raw command result object returned from MongoDB (content might vary by server version).
709
+ * @property {Number} result.ok Is 1 if the command executed correctly.
710
+ * @property {Number} result.n The total count of documents inserted.
711
+ */
712
+
713
+ /**
714
+ * @typedef {Object} Collection~insertOneWriteOpResult
715
+ * @property {Number} insertedCount The total amount of documents inserted.
716
+ * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
717
+ * @property {ObjectId} insertedId The driver generated ObjectId for the insert operation.
718
+ * @property {object} connection The connection object used for the operation.
719
+ * @property {object} result The raw command result object returned from MongoDB (content might vary by server version).
720
+ * @property {Number} result.ok Is 1 if the command executed correctly.
721
+ * @property {Number} result.n The total count of documents inserted.
722
+ */
723
+
724
+ /**
725
+ * The callback format for inserts
726
+ * @callback Collection~insertWriteOpCallback
727
+ * @param {MongoError} error An error instance representing the error during the execution.
728
+ * @param {Collection~insertWriteOpResult} result The result object if the command was executed successfully.
729
+ */
730
+
731
+ /**
732
+ * The callback format for inserts
733
+ * @callback Collection~insertOneWriteOpCallback
734
+ * @param {MongoError} error An error instance representing the error during the execution.
735
+ * @param {Collection~insertOneWriteOpResult} result The result object if the command was executed successfully.
736
+ */
737
+
738
+ /**
739
+ * Inserts a single document or a an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
740
+ * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
741
+ * can be overridden by setting the **forceServerObjectId** flag.
742
+ *
584
743
  * @method
585
744
  * @param {(object|object[])} docs Documents to insert.
586
745
  * @param {object} [options=null] Optional settings.
@@ -589,27 +748,47 @@ var insertDocuments = function(self, docs, options, callback) {
589
748
  * @param {boolean} [options.j=false] Specify a journal write concern.
590
749
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
591
750
  * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
592
- * @param {Collection~writeOpCallback} callback The command result callback
751
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
752
+ * @param {Collection~insertWriteOpCallback} [callback] The command result callback
593
753
  * @return {Promise} returns Promise if no callback passed
594
754
  * @deprecated Use insertOne, insertMany or bulkWrite
595
755
  */
596
756
  Collection.prototype.insert = function(docs, options, callback) {
597
757
  var self = this;
598
758
  if(typeof options == 'function') callback = options, options = {};
599
- options = options || {};
759
+ options = options || {ordered:false};
760
+ docs = !Array.isArray(docs) ? [docs] : docs;
600
761
 
601
- // Execute using callback
602
- if(typeof callback == 'function') return insertDocuments(self, docs, options, callback);
762
+ if(options.keepGoing == true) {
763
+ options.ordered = false;
764
+ }
603
765
 
604
- // Return a Promise
605
- return new this.s.promiseLibrary(function(resolve, reject) {
606
- insertDocuments(self, docs, options, function(err, r) {
607
- if(err) return reject(err);
608
- resolve(r);
609
- });
610
- });
766
+ return this.insertMany(docs, options, callback);
611
767
  }
612
768
 
769
+ define.classMethod('insert', {callback: true, promise:true});
770
+
771
+ /**
772
+ * @typedef {Object} Collection~updateWriteOpResult
773
+ * @property {Object} result The raw result returned from MongoDB, field will vary depending on server version.
774
+ * @property {Number} result.ok Is 1 if the command executed correctly.
775
+ * @property {Number} result.n The total count of documents scanned.
776
+ * @property {Number} result.nModified The total count of documents modified.
777
+ * @property {Object} connection The connection object used for the operation.
778
+ * @property {Number} matchedCount The number of documents that matched the filter.
779
+ * @property {Number} modifiedCount The number of documents that were modified.
780
+ * @property {Number} upsertedCount The number of documents upserted.
781
+ * @property {Object} upsertedId The upserted id.
782
+ * @property {ObjectId} upsertedId._id The upserted _id returned from the server.
783
+ */
784
+
785
+ /**
786
+ * The callback format for inserts
787
+ * @callback Collection~updateWriteOpCallback
788
+ * @param {MongoError} error An error instance representing the error during the execution.
789
+ * @param {Collection~updateWriteOpResult} result The result object if the command was executed successfully.
790
+ */
791
+
613
792
  /**
614
793
  * Update a single document on MongoDB
615
794
  * @method
@@ -620,7 +799,8 @@ Collection.prototype.insert = function(docs, options, callback) {
620
799
  * @param {(number|string)} [options.w=null] The write concern.
621
800
  * @param {number} [options.wtimeout=null] The write concern timeout.
622
801
  * @param {boolean} [options.j=false] Specify a journal write concern.
623
- * @param {Collection~writeOpCallback} callback The command result callback
802
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
803
+ * @param {Collection~updateWriteOpCallback} [callback] The command result callback
624
804
  * @return {Promise} returns Promise if no callback passed
625
805
  */
626
806
  Collection.prototype.updateOne = function(filter, update, options, callback) {
@@ -628,6 +808,12 @@ Collection.prototype.updateOne = function(filter, update, options, callback) {
628
808
  if(typeof options == 'function') callback = options, options = {};
629
809
  options = shallowClone(options)
630
810
 
811
+ // Add ignoreUndfined
812
+ if(this.s.options.ignoreUndefined) {
813
+ options = shallowClone(options);
814
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
815
+ }
816
+
631
817
  // Execute using callback
632
818
  if(typeof callback == 'function') return updateOne(self, filter, update, options, callback);
633
819
 
@@ -635,7 +821,7 @@ Collection.prototype.updateOne = function(filter, update, options, callback) {
635
821
  return new this.s.promiseLibrary(function(resolve, reject) {
636
822
  updateOne(self, filter, update, options, function(err, r) {
637
823
  if(err) return reject(err);
638
- resolve(r);
824
+ resolve(r);
639
825
  });
640
826
  });
641
827
  }
@@ -653,9 +839,11 @@ var updateOne = function(self, filter, update, options, callback) {
653
839
  r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
654
840
  r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
655
841
  if(callback) callback(null, r);
656
- });
842
+ });
657
843
  }
658
844
 
845
+ define.classMethod('updateOne', {callback: true, promise:true});
846
+
659
847
  /**
660
848
  * Replace a document on MongoDB
661
849
  * @method
@@ -666,7 +854,8 @@ var updateOne = function(self, filter, update, options, callback) {
666
854
  * @param {(number|string)} [options.w=null] The write concern.
667
855
  * @param {number} [options.wtimeout=null] The write concern timeout.
668
856
  * @param {boolean} [options.j=false] Specify a journal write concern.
669
- * @param {Collection~writeOpCallback} callback The command result callback
857
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
858
+ * @param {Collection~updateWriteOpCallback} [callback] The command result callback
670
859
  * @return {Promise} returns Promise if no callback passed
671
860
  */
672
861
  Collection.prototype.replaceOne = function(filter, update, options, callback) {
@@ -674,6 +863,12 @@ Collection.prototype.replaceOne = function(filter, update, options, callback) {
674
863
  if(typeof options == 'function') callback = options, options = {};
675
864
  options = shallowClone(options)
676
865
 
866
+ // Add ignoreUndfined
867
+ if(this.s.options.ignoreUndefined) {
868
+ options = shallowClone(options);
869
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
870
+ }
871
+
677
872
  // Execute using callback
678
873
  if(typeof callback == 'function') return replaceOne(self, filter, update, options, callback);
679
874
 
@@ -681,7 +876,7 @@ Collection.prototype.replaceOne = function(filter, update, options, callback) {
681
876
  return new this.s.promiseLibrary(function(resolve, reject) {
682
877
  replaceOne(self, filter, update, options, function(err, r) {
683
878
  if(err) return reject(err);
684
- resolve(r);
879
+ resolve(r);
685
880
  });
686
881
  });
687
882
  }
@@ -700,9 +895,11 @@ var replaceOne = function(self, filter, update, options, callback) {
700
895
  r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
701
896
  r.ops = [update];
702
897
  if(callback) callback(null, r);
703
- });
898
+ });
704
899
  }
705
900
 
901
+ define.classMethod('replaceOne', {callback: true, promise:true});
902
+
706
903
  /**
707
904
  * Update multiple documents on MongoDB
708
905
  * @method
@@ -713,7 +910,7 @@ var replaceOne = function(self, filter, update, options, callback) {
713
910
  * @param {(number|string)} [options.w=null] The write concern.
714
911
  * @param {number} [options.wtimeout=null] The write concern timeout.
715
912
  * @param {boolean} [options.j=false] Specify a journal write concern.
716
- * @param {Collection~writeOpCallback} callback The command result callback
913
+ * @param {Collection~updateWriteOpCallback} [callback] The command result callback
717
914
  * @return {Promise} returns Promise if no callback passed
718
915
  */
719
916
  Collection.prototype.updateMany = function(filter, update, options, callback) {
@@ -721,6 +918,12 @@ Collection.prototype.updateMany = function(filter, update, options, callback) {
721
918
  if(typeof options == 'function') callback = options, options = {};
722
919
  options = shallowClone(options)
723
920
 
921
+ // Add ignoreUndfined
922
+ if(this.s.options.ignoreUndefined) {
923
+ options = shallowClone(options);
924
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
925
+ }
926
+
724
927
  // Execute using callback
725
928
  if(typeof callback == 'function') return updateMany(self, filter, update, options, callback);
726
929
 
@@ -728,7 +931,7 @@ Collection.prototype.updateMany = function(filter, update, options, callback) {
728
931
  return new this.s.promiseLibrary(function(resolve, reject) {
729
932
  updateMany(self, filter, update, options, function(err, r) {
730
933
  if(err) return reject(err);
731
- resolve(r);
934
+ resolve(r);
732
935
  });
733
936
  });
734
937
  }
@@ -746,9 +949,11 @@ var updateMany = function(self, filter, update, options, callback) {
746
949
  r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
747
950
  r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
748
951
  if(callback) callback(null, r);
749
- });
952
+ });
750
953
  }
751
954
 
955
+ define.classMethod('updateMany', {callback: true, promise:true});
956
+
752
957
  var updateDocuments = function(self, selector, document, options, callback) {
753
958
  if('function' === typeof options) callback = options, options = null;
754
959
  if(options == null) options = {};
@@ -768,8 +973,8 @@ var updateDocuments = function(self, selector, document, options, callback) {
768
973
 
769
974
  // Execute the operation
770
975
  var op = {q: selector, u: document};
771
- if(options.upsert) op.upsert = true;
772
- if(options.multi) op.multi = true;
976
+ op.upsert = typeof options.upsert == 'boolean' ? options.upsert : false;
977
+ op.multi = typeof options.multi == 'boolean' ? options.multi : false;
773
978
 
774
979
  // Update options
775
980
  self.s.topology.update(self.s.namespace, [op], finalOptions, function(err, result) {
@@ -779,8 +984,8 @@ var updateDocuments = function(self, selector, document, options, callback) {
779
984
  if(result.result.code) return handleCallback(callback, toError(result.result));
780
985
  if(result.result.writeErrors) return handleCallback(callback, toError(result.result.writeErrors[0]));
781
986
  // Return the results
782
- handleCallback(callback, null, result);
783
- });
987
+ handleCallback(callback, null, result);
988
+ });
784
989
  }
785
990
 
786
991
  /**
@@ -794,13 +999,21 @@ var updateDocuments = function(self, selector, document, options, callback) {
794
999
  * @param {boolean} [options.j=false] Specify a journal write concern.
795
1000
  * @param {boolean} [options.upsert=false] Update operation is an upsert.
796
1001
  * @param {boolean} [options.multi=false] Update one/all documents with operation.
797
- * @param {Collection~writeOpCallback} callback The command result callback
1002
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
1003
+ * @param {Collection~writeOpCallback} [callback] The command result callback
798
1004
  * @throws {MongoError}
799
1005
  * @return {Promise} returns Promise if no callback passed
800
1006
  * @deprecated use updateOne, updateMany or bulkWrite
801
1007
  */
802
1008
  Collection.prototype.update = function(selector, document, options, callback) {
803
1009
  var self = this;
1010
+
1011
+ // Add ignoreUndfined
1012
+ if(this.s.options.ignoreUndefined) {
1013
+ options = shallowClone(options);
1014
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1015
+ }
1016
+
804
1017
  // Execute using callback
805
1018
  if(typeof callback == 'function') return updateDocuments(self, selector, document, options, callback);
806
1019
 
@@ -808,11 +1021,29 @@ Collection.prototype.update = function(selector, document, options, callback) {
808
1021
  return new this.s.promiseLibrary(function(resolve, reject) {
809
1022
  updateDocuments(self, selector, document, options, function(err, r) {
810
1023
  if(err) return reject(err);
811
- resolve(r);
1024
+ resolve(r);
812
1025
  });
813
1026
  });
814
1027
  }
815
1028
 
1029
+ define.classMethod('update', {callback: true, promise:true});
1030
+
1031
+ /**
1032
+ * @typedef {Object} Collection~deleteWriteOpResult
1033
+ * @property {Object} result The raw result returned from MongoDB, field will vary depending on server version.
1034
+ * @property {Number} result.ok Is 1 if the command executed correctly.
1035
+ * @property {Number} result.n The total count of documents deleted.
1036
+ * @property {Object} connection The connection object used for the operation.
1037
+ * @property {Number} deletedCount The number of documents deleted.
1038
+ */
1039
+
1040
+ /**
1041
+ * The callback format for inserts
1042
+ * @callback Collection~deleteWriteOpCallback
1043
+ * @param {MongoError} error An error instance representing the error during the execution.
1044
+ * @param {Collection~deleteWriteOpResult} result The result object if the command was executed successfully.
1045
+ */
1046
+
816
1047
  /**
817
1048
  * Delete a document on MongoDB
818
1049
  * @method
@@ -821,13 +1052,20 @@ Collection.prototype.update = function(selector, document, options, callback) {
821
1052
  * @param {(number|string)} [options.w=null] The write concern.
822
1053
  * @param {number} [options.wtimeout=null] The write concern timeout.
823
1054
  * @param {boolean} [options.j=false] Specify a journal write concern.
824
- * @param {Collection~writeOpCallback} callback The command result callback
1055
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
1056
+ * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
825
1057
  * @return {Promise} returns Promise if no callback passed
826
1058
  */
827
1059
  Collection.prototype.deleteOne = function(filter, options, callback) {
828
1060
  var self = this;
829
1061
  if(typeof options == 'function') callback = options, options = {};
830
- var options = shallowClone(options);
1062
+ var options = shallowClone(options);
1063
+
1064
+ // Add ignoreUndfined
1065
+ if(this.s.options.ignoreUndefined) {
1066
+ options = shallowClone(options);
1067
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1068
+ }
831
1069
 
832
1070
  // Execute using callback
833
1071
  if(typeof callback == 'function') return deleteOne(self, filter, options, callback);
@@ -836,7 +1074,7 @@ Collection.prototype.deleteOne = function(filter, options, callback) {
836
1074
  return new this.s.promiseLibrary(function(resolve, reject) {
837
1075
  deleteOne(self, filter, options, function(err, r) {
838
1076
  if(err) return reject(err);
839
- resolve(r);
1077
+ resolve(r);
840
1078
  });
841
1079
  });
842
1080
  }
@@ -849,11 +1087,15 @@ var deleteOne = function(self, filter, options, callback) {
849
1087
  if(r == null) return callback(null, {result: {ok:1}});
850
1088
  r.deletedCount = r.result.n;
851
1089
  if(callback) callback(null, r);
852
- });
1090
+ });
853
1091
  }
854
1092
 
1093
+ define.classMethod('deleteOne', {callback: true, promise:true});
1094
+
855
1095
  Collection.prototype.removeOne = Collection.prototype.deleteOne;
856
1096
 
1097
+ define.classMethod('removeOne', {callback: true, promise:true});
1098
+
857
1099
  /**
858
1100
  * Delete multiple documents on MongoDB
859
1101
  * @method
@@ -862,13 +1104,19 @@ Collection.prototype.removeOne = Collection.prototype.deleteOne;
862
1104
  * @param {(number|string)} [options.w=null] The write concern.
863
1105
  * @param {number} [options.wtimeout=null] The write concern timeout.
864
1106
  * @param {boolean} [options.j=false] Specify a journal write concern.
865
- * @param {Collection~writeOpCallback} callback The command result callback
1107
+ * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
866
1108
  * @return {Promise} returns Promise if no callback passed
867
1109
  */
868
1110
  Collection.prototype.deleteMany = function(filter, options, callback) {
869
1111
  var self = this;
870
1112
  if(typeof options == 'function') callback = options, options = {};
871
- var options = shallowClone(options);
1113
+ var options = shallowClone(options);
1114
+
1115
+ // Add ignoreUndfined
1116
+ if(this.s.options.ignoreUndefined) {
1117
+ options = shallowClone(options);
1118
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1119
+ }
872
1120
 
873
1121
  // Execute using callback
874
1122
  if(typeof callback == 'function') return deleteMany(self, filter, options, callback);
@@ -877,7 +1125,7 @@ Collection.prototype.deleteMany = function(filter, options, callback) {
877
1125
  return new this.s.promiseLibrary(function(resolve, reject) {
878
1126
  deleteMany(self, filter, options, function(err, r) {
879
1127
  if(err) return reject(err);
880
- resolve(r);
1128
+ resolve(r);
881
1129
  });
882
1130
  });
883
1131
  }
@@ -890,11 +1138,9 @@ var deleteMany = function(self, filter, options, callback) {
890
1138
  if(r == null) return callback(null, {result: {ok:1}});
891
1139
  r.deletedCount = r.result.n;
892
1140
  if(callback) callback(null, r);
893
- });
1141
+ });
894
1142
  }
895
1143
 
896
- Collection.prototype.removeMany = Collection.prototype.deleteMany;
897
-
898
1144
  var removeDocuments = function(self, selector, options, callback) {
899
1145
  if(typeof options == 'function') {
900
1146
  callback = options, options = {};
@@ -925,10 +1171,16 @@ var removeDocuments = function(self, selector, options, callback) {
925
1171
  if(result.result.code) return handleCallback(callback, toError(result.result));
926
1172
  if(result.result.writeErrors) return handleCallback(callback, toError(result.result.writeErrors[0]));
927
1173
  // Return the results
928
- handleCallback(callback, null, result);
929
- });
1174
+ handleCallback(callback, null, result);
1175
+ });
930
1176
  }
931
1177
 
1178
+ define.classMethod('deleteMany', {callback: true, promise:true});
1179
+
1180
+ Collection.prototype.removeMany = Collection.prototype.deleteMany;
1181
+
1182
+ define.classMethod('removeMany', {callback: true, promise:true});
1183
+
932
1184
  /**
933
1185
  * Remove documents.
934
1186
  * @method
@@ -938,12 +1190,19 @@ var removeDocuments = function(self, selector, options, callback) {
938
1190
  * @param {number} [options.wtimeout=null] The write concern timeout.
939
1191
  * @param {boolean} [options.j=false] Specify a journal write concern.
940
1192
  * @param {boolean} [options.single=false] Removes the first document found.
941
- * @param {Collection~writeOpCallback} callback The command result callback
1193
+ * @param {Collection~writeOpCallback} [callback] The command result callback
942
1194
  * @return {Promise} returns Promise if no callback passed
943
1195
  * @deprecated use deleteOne, deleteMany or bulkWrite
944
1196
  */
945
1197
  Collection.prototype.remove = function(selector, options, callback) {
946
1198
  var self = this;
1199
+
1200
+ // Add ignoreUndfined
1201
+ if(this.s.options.ignoreUndefined) {
1202
+ options = shallowClone(options);
1203
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1204
+ }
1205
+
947
1206
  // Execute using callback
948
1207
  if(typeof callback == 'function') return removeDocuments(self, selector, options, callback);
949
1208
 
@@ -951,11 +1210,13 @@ Collection.prototype.remove = function(selector, options, callback) {
951
1210
  return new this.s.promiseLibrary(function(resolve, reject) {
952
1211
  removeDocuments(self, selector, options, function(err, r) {
953
1212
  if(err) return reject(err);
954
- resolve(r);
1213
+ resolve(r);
955
1214
  });
956
1215
  });
957
1216
  }
958
1217
 
1218
+ define.classMethod('remove', {callback: true, promise:true});
1219
+
959
1220
  /**
960
1221
  * Save a document. Simple full document replacement function. Not recommended for efficiency, use atomic
961
1222
  * operators and update instead for more efficient operations.
@@ -965,14 +1226,21 @@ Collection.prototype.remove = function(selector, options, callback) {
965
1226
  * @param {(number|string)} [options.w=null] The write concern.
966
1227
  * @param {number} [options.wtimeout=null] The write concern timeout.
967
1228
  * @param {boolean} [options.j=false] Specify a journal write concern.
968
- * @param {Collection~writeOpCallback} callback The command result callback
1229
+ * @param {Collection~writeOpCallback} [callback] The command result callback
969
1230
  * @return {Promise} returns Promise if no callback passed
1231
+ * @deprecated use insertOne, insertMany, updateOne or updateMany
970
1232
  */
971
1233
  Collection.prototype.save = function(doc, options, callback) {
972
1234
  var self = this;
973
1235
  if(typeof options == 'function') callback = options, options = {};
974
1236
  options = options || {};
975
1237
 
1238
+ // Add ignoreUndfined
1239
+ if(this.s.options.ignoreUndefined) {
1240
+ options = shallowClone(options);
1241
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1242
+ }
1243
+
976
1244
  // Execute using callback
977
1245
  if(typeof callback == 'function') return save(self, doc, options, callback);
978
1246
 
@@ -980,7 +1248,7 @@ Collection.prototype.save = function(doc, options, callback) {
980
1248
  return new this.s.promiseLibrary(function(resolve, reject) {
981
1249
  save(self, doc, options, function(err, r) {
982
1250
  if(err) return reject(err);
983
- resolve(r);
1251
+ resolve(r);
984
1252
  });
985
1253
  });
986
1254
  }
@@ -1000,9 +1268,11 @@ var save = function(self, doc, options, callback) {
1000
1268
  if(doc == null) return handleCallback(callback, null, null);
1001
1269
  if(err) return handleCallback(callback, err, null);
1002
1270
  handleCallback(callback, null, r);
1003
- });
1271
+ });
1004
1272
  }
1005
1273
 
1274
+ define.classMethod('save', {callback: true, promise:true});
1275
+
1006
1276
  /**
1007
1277
  * The callback format for results
1008
1278
  * @callback Collection~resultCallback
@@ -1017,7 +1287,7 @@ var save = function(self, doc, options, callback) {
1017
1287
  * @param {object} [options=null] Optional settings.
1018
1288
  * @param {number} [options.limit=0] Sets the limit of documents returned in the query.
1019
1289
  * @param {(array|object)} [options.sort=null] Set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
1020
- * @param {object} [options.fields=null] The fields to return in the query. Object of fields to include or exclude (not both), {'a':1}
1290
+ * @param {object} [options.fields=null] The fields to return in the query. Object of fields to include or exclude (not both), {'a':1}
1021
1291
  * @param {number} [options.skip=0] Set to skip N documents ahead in your query (useful for pagination).
1022
1292
  * @param {Object} [options.hint=null] Tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
1023
1293
  * @param {boolean} [options.explain=false] Explain the query instead of returning the data.
@@ -1026,7 +1296,7 @@ var save = function(self, doc, options, callback) {
1026
1296
  * @param {boolean} [options.tailable=false] Specify if the cursor is tailable.
1027
1297
  * @param {number} [options.batchSize=0] Set the batchSize for the getMoreCommand when iterating over the query results.
1028
1298
  * @param {boolean} [options.returnKey=false] Only return the index key.
1029
- * @param {number} [options.maxScan=null] Limit the number of items to scan.
1299
+ * @param {number} [options.maxScan=null] Limit the number of items to scan.
1030
1300
  * @param {number} [options.min=null] Set index bounds.
1031
1301
  * @param {number} [options.max=null] Set index bounds.
1032
1302
  * @param {boolean} [options.showDiskLoc=false] Show disk location of results.
@@ -1035,10 +1305,11 @@ var save = function(self, doc, options, callback) {
1035
1305
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1036
1306
  * @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
1037
1307
  * @param {number} [options.maxTimeMS=null] Number of miliseconds to wait before aborting the query.
1038
- * @param {Collection~resultCallback} callback The command result callback
1308
+ * @param {Collection~resultCallback} [callback] The command result callback
1039
1309
  * @return {Promise} returns Promise if no callback passed
1310
+ * @deprecated use find().limit(1).next(function(err, doc){})
1040
1311
  */
1041
- Collection.prototype.findOne = function() {
1312
+ Collection.prototype.findOne = function() {
1042
1313
  var self = this;
1043
1314
  var args = Array.prototype.slice.call(arguments, 0);
1044
1315
  var callback = args.pop();
@@ -1051,7 +1322,7 @@ Collection.prototype.findOne = function() {
1051
1322
  return new this.s.promiseLibrary(function(resolve, reject) {
1052
1323
  findOne(self, args, function(err, r) {
1053
1324
  if(err) return reject(err);
1054
- resolve(r);
1325
+ resolve(r);
1055
1326
  });
1056
1327
  });
1057
1328
  }
@@ -1065,6 +1336,8 @@ var findOne = function(self, args, callback) {
1065
1336
  });
1066
1337
  }
1067
1338
 
1339
+ define.classMethod('findOne', {callback: true, promise:true});
1340
+
1068
1341
  /**
1069
1342
  * The callback format for the collection method, must be used if strict is specified
1070
1343
  * @callback Collection~collectionResultCallback
@@ -1079,7 +1352,7 @@ var findOne = function(self, args, callback) {
1079
1352
  * @param {string} newName New name of of the collection.
1080
1353
  * @param {object} [options=null] Optional settings.
1081
1354
  * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
1082
- * @param {Collection~collectionResultCallback} callback The results callback
1355
+ * @param {Collection~collectionResultCallback} [callback] The results callback
1083
1356
  * @return {Promise} returns Promise if no callback passed
1084
1357
  */
1085
1358
  Collection.prototype.rename = function(newName, opt, callback) {
@@ -1094,7 +1367,7 @@ Collection.prototype.rename = function(newName, opt, callback) {
1094
1367
  return new this.s.promiseLibrary(function(resolve, reject) {
1095
1368
  rename(self, newName, opt, function(err, r) {
1096
1369
  if(err) return reject(err);
1097
- resolve(r);
1370
+ resolve(r);
1098
1371
  });
1099
1372
  });
1100
1373
  }
@@ -1118,14 +1391,16 @@ var rename = function(self, newName, opt, callback) {
1118
1391
  } catch(err) {
1119
1392
  return handleCallback(callback, toError(err), null);
1120
1393
  }
1121
- });
1394
+ });
1122
1395
  }
1123
1396
 
1397
+ define.classMethod('rename', {callback: true, promise:true});
1398
+
1124
1399
  /**
1125
1400
  * Drop the collection from the database, removing it permanently. New accesses will create a new collection.
1126
1401
  *
1127
1402
  * @method
1128
- * @param {Collection~resultCallback} callback The results callback
1403
+ * @param {Collection~resultCallback} [callback] The results callback
1129
1404
  * @return {Promise} returns Promise if no callback passed
1130
1405
  */
1131
1406
  Collection.prototype.drop = function(callback) {
@@ -1137,16 +1412,18 @@ Collection.prototype.drop = function(callback) {
1137
1412
  return new this.s.promiseLibrary(function(resolve, reject) {
1138
1413
  self.s.db.dropCollection(self.s.name, function(err, r) {
1139
1414
  if(err) return reject(err);
1140
- resolve(r);
1415
+ resolve(r);
1141
1416
  });
1142
1417
  });
1143
1418
  }
1144
1419
 
1420
+ define.classMethod('drop', {callback: true, promise:true});
1421
+
1145
1422
  /**
1146
1423
  * Returns the options of the collection.
1147
1424
  *
1148
1425
  * @method
1149
- * @param {Collection~resultCallback} callback The results callback
1426
+ * @param {Collection~resultCallback} [callback] The results callback
1150
1427
  * @return {Promise} returns Promise if no callback passed
1151
1428
  */
1152
1429
  Collection.prototype.options = function(callback) {
@@ -1159,7 +1436,7 @@ Collection.prototype.options = function(callback) {
1159
1436
  return new this.s.promiseLibrary(function(resolve, reject) {
1160
1437
  options(self, function(err, r) {
1161
1438
  if(err) return reject(err);
1162
- resolve(r);
1439
+ resolve(r);
1163
1440
  });
1164
1441
  });
1165
1442
  }
@@ -1167,16 +1444,21 @@ Collection.prototype.options = function(callback) {
1167
1444
  var options = function(self, callback) {
1168
1445
  self.s.db.listCollections({name: self.s.name}).toArray(function(err, collections) {
1169
1446
  if(err) return handleCallback(callback, err);
1170
- if(collections.length == 0) return handleCallback(callback, new MongoError(f("collection %s not found", self.s.namespace)));
1171
- handleCallback(callback, err, collections[0].options || null);
1172
- });
1447
+ if(collections.length == 0) {
1448
+ return handleCallback(callback, MongoError.create({message: f("collection %s not found", self.s.namespace), driver:true }));
1449
+ }
1450
+
1451
+ handleCallback(callback, err, collections[0].options || null);
1452
+ });
1173
1453
  }
1174
1454
 
1455
+ define.classMethod('options', {callback: true, promise:true});
1456
+
1175
1457
  /**
1176
1458
  * Returns if the collection is a capped collection
1177
1459
  *
1178
1460
  * @method
1179
- * @param {Collection~resultCallback} callback The results callback
1461
+ * @param {Collection~resultCallback} [callback] The results callback
1180
1462
  * @return {Promise} returns Promise if no callback passed
1181
1463
  */
1182
1464
  Collection.prototype.isCapped = function(callback) {
@@ -1189,7 +1471,7 @@ Collection.prototype.isCapped = function(callback) {
1189
1471
  return new this.s.promiseLibrary(function(resolve, reject) {
1190
1472
  isCapped(self, function(err, r) {
1191
1473
  if(err) return reject(err);
1192
- resolve(r);
1474
+ resolve(r);
1193
1475
  });
1194
1476
  });
1195
1477
  }
@@ -1198,9 +1480,11 @@ var isCapped = function(self, callback) {
1198
1480
  self.options(function(err, document) {
1199
1481
  if(err) return handleCallback(callback, err);
1200
1482
  handleCallback(callback, null, document && document.capped);
1201
- });
1483
+ });
1202
1484
  }
1203
1485
 
1486
+ define.classMethod('isCapped', {callback: true, promise:true});
1487
+
1204
1488
  /**
1205
1489
  * Creates an index on the db and collection collection.
1206
1490
  * @method
@@ -1218,7 +1502,7 @@ var isCapped = function(self, callback) {
1218
1502
  * @param {number} [options.v=null] Specify the format version of the indexes.
1219
1503
  * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
1220
1504
  * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
1221
- * @param {Collection~resultCallback} callback The command result callback
1505
+ * @param {Collection~resultCallback} [callback] The command result callback
1222
1506
  * @return {Promise} returns Promise if no callback passed
1223
1507
  */
1224
1508
  Collection.prototype.createIndex = function(fieldOrSpec, options, callback) {
@@ -1237,22 +1521,24 @@ Collection.prototype.createIndex = function(fieldOrSpec, options, callback) {
1237
1521
  return new this.s.promiseLibrary(function(resolve, reject) {
1238
1522
  createIndex(self, fieldOrSpec, options, function(err, r) {
1239
1523
  if(err) return reject(err);
1240
- resolve(r);
1524
+ resolve(r);
1241
1525
  });
1242
1526
  });
1243
1527
  }
1244
1528
 
1245
1529
  var createIndex = function(self, fieldOrSpec, options, callback) {
1246
- self.s.db.createIndex(self.s.name, fieldOrSpec, options, callback);
1530
+ self.s.db.createIndex(self.s.name, fieldOrSpec, options, callback);
1247
1531
  }
1248
1532
 
1533
+ define.classMethod('createIndex', {callback: true, promise:true});
1534
+
1249
1535
  /**
1250
1536
  * Creates multiple indexes in the collection, this method is only supported for
1251
1537
  * MongoDB 2.6 or higher. Earlier version of MongoDB will throw a command not supported
1252
1538
  * error. Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/.
1253
1539
  * @method
1254
- * @param {array} indexSpecs An array of index specifications to be created
1255
- * @param {Collection~resultCallback} callback The command result callback
1540
+ * @param {array} indexSpecs An array of index specifications to be created
1541
+ * @param {Collection~resultCallback} [callback] The command result callback
1256
1542
  * @return {Promise} returns Promise if no callback passed
1257
1543
  */
1258
1544
  Collection.prototype.createIndexes = function(indexSpecs, callback) {
@@ -1265,7 +1551,7 @@ Collection.prototype.createIndexes = function(indexSpecs, callback) {
1265
1551
  return new this.s.promiseLibrary(function(resolve, reject) {
1266
1552
  createIndexes(self, indexSpecs, function(err, r) {
1267
1553
  if(err) return reject(err);
1268
- resolve(r);
1554
+ resolve(r);
1269
1555
  });
1270
1556
  });
1271
1557
  }
@@ -1286,11 +1572,13 @@ var createIndexes = function(self, indexSpecs, callback) {
1286
1572
  }
1287
1573
 
1288
1574
  // Execute the index
1289
- self.s.db.command({
1575
+ self.s.db.command({
1290
1576
  createIndexes: self.s.name, indexes: indexSpecs
1291
- }, callback);
1577
+ }, callback);
1292
1578
  }
1293
1579
 
1580
+ define.classMethod('createIndexes', {callback: true, promise:true});
1581
+
1294
1582
  /**
1295
1583
  * Drops an index from this collection.
1296
1584
  * @method
@@ -1299,7 +1587,7 @@ var createIndexes = function(self, indexSpecs, callback) {
1299
1587
  * @param {(number|string)} [options.w=null] The write concern.
1300
1588
  * @param {number} [options.wtimeout=null] The write concern timeout.
1301
1589
  * @param {boolean} [options.j=false] Specify a journal write concern.
1302
- * @param {Collection~resultCallback} callback The command result callback
1590
+ * @param {Collection~resultCallback} [callback] The command result callback
1303
1591
  * @return {Promise} returns Promise if no callback passed
1304
1592
  */
1305
1593
  Collection.prototype.dropIndex = function(indexName, options, callback) {
@@ -1318,27 +1606,29 @@ Collection.prototype.dropIndex = function(indexName, options, callback) {
1318
1606
  return new this.s.promiseLibrary(function(resolve, reject) {
1319
1607
  dropIndex(self, indexName, options, function(err, r) {
1320
1608
  if(err) return reject(err);
1321
- resolve(r);
1609
+ resolve(r);
1322
1610
  });
1323
1611
  });
1324
1612
  }
1325
1613
 
1326
1614
  var dropIndex = function(self, indexName, options, callback) {
1327
1615
  // Delete index command
1328
- var cmd = {'deleteIndexes':self.s.name, 'index':indexName};
1616
+ var cmd = {'deleteIndexes':self.s.name, 'index':indexName};
1329
1617
 
1330
1618
  // Execute command
1331
1619
  self.s.db.command(cmd, options, function(err, result) {
1332
1620
  if(typeof callback != 'function') return;
1333
1621
  if(err) return handleCallback(callback, err, null);
1334
1622
  handleCallback(callback, null, result);
1335
- });
1623
+ });
1336
1624
  }
1337
1625
 
1626
+ define.classMethod('dropIndex', {callback: true, promise:true});
1627
+
1338
1628
  /**
1339
1629
  * Drops all indexes from this collection.
1340
1630
  * @method
1341
- * @param {Collection~resultCallback} callback The command result callback
1631
+ * @param {Collection~resultCallback} [callback] The command result callback
1342
1632
  * @return {Promise} returns Promise if no callback passed
1343
1633
  */
1344
1634
  Collection.prototype.dropIndexes = function(callback) {
@@ -1351,7 +1641,7 @@ Collection.prototype.dropIndexes = function(callback) {
1351
1641
  return new this.s.promiseLibrary(function(resolve, reject) {
1352
1642
  dropIndexes(self, function(err, r) {
1353
1643
  if(err) return reject(err);
1354
- resolve(r);
1644
+ resolve(r);
1355
1645
  });
1356
1646
  });
1357
1647
  }
@@ -1363,27 +1653,31 @@ var dropIndexes = function(self, callback) {
1363
1653
  });
1364
1654
  }
1365
1655
 
1656
+ define.classMethod('dropIndexes', {callback: true, promise:true});
1657
+
1366
1658
  /**
1367
1659
  * Drops all indexes from this collection.
1368
1660
  * @method
1369
1661
  * @deprecated use dropIndexes
1370
1662
  * @param {Collection~resultCallback} callback The command result callback
1371
- * @return {Promise} returns Promise if no callback passed
1663
+ * @return {Promise} returns Promise if no [callback] passed
1372
1664
  */
1373
1665
  Collection.prototype.dropAllIndexes = Collection.prototype.dropIndexes;
1374
1666
 
1667
+ define.classMethod('dropAllIndexes', {callback: true, promise:true});
1668
+
1375
1669
  /**
1376
1670
  * Reindex all indexes on the collection
1377
1671
  * Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
1378
1672
  * @method
1379
- * @param {Collection~resultCallback} callback The command result callback
1673
+ * @param {Collection~resultCallback} [callback] The command result callback
1380
1674
  * @return {Promise} returns Promise if no callback passed
1381
1675
  */
1382
1676
  Collection.prototype.reIndex = function(options, callback) {
1383
1677
  var self = this;
1384
1678
  if(typeof options == 'function') callback = options, options = {};
1385
1679
  options = options || {};
1386
-
1680
+
1387
1681
  // Execute using callback
1388
1682
  if(typeof callback == 'function') return reIndex(self, options, callback);
1389
1683
 
@@ -1391,7 +1685,7 @@ Collection.prototype.reIndex = function(options, callback) {
1391
1685
  return new this.s.promiseLibrary(function(resolve, reject) {
1392
1686
  reIndex(self, options, function(err, r) {
1393
1687
  if(err) return reject(err);
1394
- resolve(r);
1688
+ resolve(r);
1395
1689
  });
1396
1690
  });
1397
1691
  }
@@ -1405,15 +1699,18 @@ var reIndex = function(self, options, callback) {
1405
1699
  if(callback == null) return;
1406
1700
  if(err) return handleCallback(callback, err, null);
1407
1701
  handleCallback(callback, null, result.ok ? true : false);
1408
- });
1702
+ });
1409
1703
  }
1410
1704
 
1705
+ define.classMethod('reIndex', {callback: true, promise:true});
1706
+
1411
1707
  /**
1412
1708
  * Get the list of all indexes information for the collection.
1413
1709
  *
1414
1710
  * @method
1415
1711
  * @param {object} [options=null] Optional settings.
1416
1712
  * @param {number} [options.batchSize=null] The batchSize for the returned command cursor or if pre 2.8 the systems batch collection
1713
+ * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1417
1714
  * @return {CommandCursor}
1418
1715
  */
1419
1716
  Collection.prototype.listIndexes = function(options) {
@@ -1425,22 +1722,38 @@ Collection.prototype.listIndexes = function(options) {
1425
1722
  // Set the promiseLibrary
1426
1723
  options.promiseLibrary = this.s.promiseLibrary;
1427
1724
 
1725
+ if(!this.s.topology.capabilities()) {
1726
+ throw new MongoError('cannot connect to server');
1727
+ }
1728
+
1428
1729
  // We have a list collections command
1429
- if(this.s.db.serverConfig.capabilities().hasListIndexesCommand) {
1730
+ if(this.s.topology.capabilities().hasListIndexesCommand) {
1430
1731
  // Cursor options
1431
1732
  var cursor = options.batchSize ? {batchSize: options.batchSize} : {}
1432
1733
  // Build the command
1433
1734
  var command = { listIndexes: this.s.name, cursor: cursor };
1434
1735
  // Execute the cursor
1435
- return this.s.topology.cursor(f('%s.$cmd', this.s.dbName), command, options);
1736
+ var cursor = this.s.topology.cursor(f('%s.$cmd', this.s.dbName), command, options);
1737
+ // Do we have a readPreference, apply it
1738
+ if(options.readPeference) cursor.setReadPreference(options.readPeference);
1739
+ // Return the cursor
1740
+ return cursor;
1436
1741
  }
1437
1742
 
1438
1743
  // Get the namespace
1439
1744
  var ns = f('%s.system.indexes', this.s.dbName);
1440
1745
  // Get the query
1441
- return this.s.topology.cursor(ns, {find: ns, query: {ns: this.s.namespace}}, options);
1746
+ var cursor = this.s.topology.cursor(ns, {find: ns, query: {ns: this.s.namespace}}, options);
1747
+ // Do we have a readPreference, apply it
1748
+ if(options.readPeference) cursor.setReadPreference(options.readPeference);
1749
+ // Set the passed in batch size if one was provided
1750
+ if(options.batchSize) cursor = cursor.batchSize(options.batchSize);
1751
+ // Return the cursor
1752
+ return cursor;
1442
1753
  };
1443
1754
 
1755
+ define.classMethod('listIndexes', {callback: false, promise:false, returns: [CommandCursor]});
1756
+
1444
1757
  /**
1445
1758
  * Ensures that an index exists, if it does not it creates it
1446
1759
  * @method
@@ -1459,7 +1772,7 @@ Collection.prototype.listIndexes = function(options) {
1459
1772
  * @param {number} [options.v=null] Specify the format version of the indexes.
1460
1773
  * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
1461
1774
  * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
1462
- * @param {Collection~resultCallback} callback The command result callback
1775
+ * @param {Collection~resultCallback} [callback] The command result callback
1463
1776
  * @return {Promise} returns Promise if no callback passed
1464
1777
  */
1465
1778
  Collection.prototype.ensureIndex = function(fieldOrSpec, options, callback) {
@@ -1474,20 +1787,22 @@ Collection.prototype.ensureIndex = function(fieldOrSpec, options, callback) {
1474
1787
  return new this.s.promiseLibrary(function(resolve, reject) {
1475
1788
  ensureIndex(self, fieldOrSpec, options, function(err, r) {
1476
1789
  if(err) return reject(err);
1477
- resolve(r);
1790
+ resolve(r);
1478
1791
  });
1479
1792
  });
1480
1793
  }
1481
1794
 
1482
1795
  var ensureIndex = function(self, fieldOrSpec, options, callback) {
1483
- self.s.db.ensureIndex(self.s.name, fieldOrSpec, options, callback);
1796
+ self.s.db.ensureIndex(self.s.name, fieldOrSpec, options, callback);
1484
1797
  }
1485
1798
 
1799
+ define.classMethod('ensureIndex', {callback: true, promise:true});
1800
+
1486
1801
  /**
1487
1802
  * Checks if one or more indexes exist on the collection, fails on first non-existing index
1488
1803
  * @method
1489
1804
  * @param {(string|array)} indexes One or more index names to check.
1490
- * @param {Collection~resultCallback} callback The command result callback
1805
+ * @param {Collection~resultCallback} [callback] The command result callback
1491
1806
  * @return {Promise} returns Promise if no callback passed
1492
1807
  */
1493
1808
  Collection.prototype.indexExists = function(indexes, callback) {
@@ -1500,7 +1815,7 @@ Collection.prototype.indexExists = function(indexes, callback) {
1500
1815
  return new this.s.promiseLibrary(function(resolve, reject) {
1501
1816
  indexExists(self, indexes, function(err, r) {
1502
1817
  if(err) return reject(err);
1503
- resolve(r);
1818
+ resolve(r);
1504
1819
  });
1505
1820
  });
1506
1821
  }
@@ -1520,15 +1835,17 @@ var indexExists = function(self, indexes, callback) {
1520
1835
 
1521
1836
  // All keys found return true
1522
1837
  return handleCallback(callback, null, true);
1523
- });
1838
+ });
1524
1839
  }
1525
1840
 
1841
+ define.classMethod('indexExists', {callback: true, promise:true});
1842
+
1526
1843
  /**
1527
1844
  * Retrieves this collections index info.
1528
1845
  * @method
1529
1846
  * @param {object} [options=null] Optional settings.
1530
1847
  * @param {boolean} [options.full=false] Returns the full raw index information.
1531
- * @param {Collection~resultCallback} callback The command result callback
1848
+ * @param {Collection~resultCallback} [callback] The command result callback
1532
1849
  * @return {Promise} returns Promise if no callback passed
1533
1850
  */
1534
1851
  Collection.prototype.indexInformation = function(options, callback) {
@@ -1546,15 +1863,17 @@ Collection.prototype.indexInformation = function(options, callback) {
1546
1863
  return new this.s.promiseLibrary(function(resolve, reject) {
1547
1864
  indexInformation(self, options, function(err, r) {
1548
1865
  if(err) return reject(err);
1549
- resolve(r);
1866
+ resolve(r);
1550
1867
  });
1551
1868
  });
1552
1869
  }
1553
1870
 
1554
1871
  var indexInformation = function(self, options, callback) {
1555
- self.s.db.indexInformation(self.s.name, options, callback);
1872
+ self.s.db.indexInformation(self.s.name, options, callback);
1556
1873
  }
1557
1874
 
1875
+ define.classMethod('indexInformation', {callback: true, promise:true});
1876
+
1558
1877
  /**
1559
1878
  * The callback format for results
1560
1879
  * @callback Collection~countCallback
@@ -1571,7 +1890,7 @@ var indexInformation = function(self, options, callback) {
1571
1890
  * @param {boolean} [options.skip=null] The number of documents to skip for the count.
1572
1891
  * @param {string} [options.hint=null] An index name hint for the query.
1573
1892
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1574
- * @param {Collection~countCallback} callback The command result callback
1893
+ * @param {Collection~countCallback} [callback] The command result callback
1575
1894
  * @return {Promise} returns Promise if no callback passed
1576
1895
  */
1577
1896
  Collection.prototype.count = function(query, options, callback) {
@@ -1593,7 +1912,7 @@ Collection.prototype.count = function(query, options, callback) {
1593
1912
  return new this.s.promiseLibrary(function(resolve, reject) {
1594
1913
  count(self, query, options, function(err, r) {
1595
1914
  if(err) return reject(err);
1596
- resolve(r);
1915
+ resolve(r);
1597
1916
  });
1598
1917
  });
1599
1918
  };
@@ -1606,8 +1925,7 @@ var count = function(self, query, options, callback) {
1606
1925
 
1607
1926
  // Final query
1608
1927
  var cmd = {
1609
- 'count': self.s.name, 'query': query
1610
- , 'fields': null
1928
+ 'count': self.s.name, 'query': query
1611
1929
  };
1612
1930
 
1613
1931
  // Add limit and skip if defined
@@ -1618,13 +1936,20 @@ var count = function(self, query, options, callback) {
1618
1936
  // Ensure we have the right read preference inheritance
1619
1937
  options = getReadPreference(self, options, self.s.db, self);
1620
1938
 
1939
+ // Do we have a readConcern specified
1940
+ if(self.s.readConcern) {
1941
+ cmd.readConcern = self.s.readConcern;
1942
+ }
1943
+
1621
1944
  // Execute command
1622
1945
  self.s.db.command(cmd, options, function(err, result) {
1623
1946
  if(err) return handleCallback(callback, err);
1624
1947
  handleCallback(callback, null, result.n);
1625
- });
1948
+ });
1626
1949
  }
1627
1950
 
1951
+ define.classMethod('count', {callback: true, promise:true});
1952
+
1628
1953
  /**
1629
1954
  * The distinct command returns returns a list of distinct values for the given key across a collection.
1630
1955
  * @method
@@ -1632,7 +1957,7 @@ var count = function(self, query, options, callback) {
1632
1957
  * @param {object} query The query for filtering the set of documents to which we apply the distinct filter.
1633
1958
  * @param {object} [options=null] Optional settings.
1634
1959
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1635
- * @param {Collection~resultCallback} callback The command result callback
1960
+ * @param {Collection~resultCallback} [callback] The command result callback
1636
1961
  * @return {Promise} returns Promise if no callback passed
1637
1962
  */
1638
1963
  Collection.prototype.distinct = function(key, query, options, callback) {
@@ -1654,7 +1979,7 @@ Collection.prototype.distinct = function(key, query, options, callback) {
1654
1979
  return new this.s.promiseLibrary(function(resolve, reject) {
1655
1980
  distinct(self, key, query, options, function(err, r) {
1656
1981
  if(err) return reject(err);
1657
- resolve(r);
1982
+ resolve(r);
1658
1983
  });
1659
1984
  });
1660
1985
  };
@@ -1671,17 +1996,24 @@ var distinct = function(self, key, query, options, callback) {
1671
1996
  // Ensure we have the right read preference inheritance
1672
1997
  options = getReadPreference(self, options, self.s.db, self);
1673
1998
 
1999
+ // Do we have a readConcern specified
2000
+ if(self.s.readConcern) {
2001
+ cmd.readConcern = self.s.readConcern;
2002
+ }
2003
+
1674
2004
  // Execute the command
1675
2005
  self.s.db.command(cmd, options, function(err, result) {
1676
2006
  if(err) return handleCallback(callback, err);
1677
2007
  handleCallback(callback, null, result.values);
1678
- });
2008
+ });
1679
2009
  }
1680
2010
 
2011
+ define.classMethod('distinct', {callback: true, promise:true});
2012
+
1681
2013
  /**
1682
2014
  * Retrieve all the indexes on the collection.
1683
2015
  * @method
1684
- * @param {Collection~resultCallback} callback The command result callback
2016
+ * @param {Collection~resultCallback} [callback] The command result callback
1685
2017
  * @return {Promise} returns Promise if no callback passed
1686
2018
  */
1687
2019
  Collection.prototype.indexes = function(callback) {
@@ -1693,22 +2025,24 @@ Collection.prototype.indexes = function(callback) {
1693
2025
  return new this.s.promiseLibrary(function(resolve, reject) {
1694
2026
  indexes(self, function(err, r) {
1695
2027
  if(err) return reject(err);
1696
- resolve(r);
2028
+ resolve(r);
1697
2029
  });
1698
2030
  });
1699
2031
  }
1700
2032
 
1701
2033
  var indexes = function(self, callback) {
1702
- self.s.db.indexInformation(self.s.name, {full:true}, callback);
2034
+ self.s.db.indexInformation(self.s.name, {full:true}, callback);
1703
2035
  }
1704
2036
 
2037
+ define.classMethod('indexes', {callback: true, promise:true});
2038
+
1705
2039
  /**
1706
2040
  * Get all the collection statistics.
1707
2041
  *
1708
2042
  * @method
1709
2043
  * @param {object} [options=null] Optional settings.
1710
2044
  * @param {number} [options.scale=null] Divide the returned sizes by scale value.
1711
- * @param {Collection~resultCallback} callback The collection result callback
2045
+ * @param {Collection~resultCallback} [callback] The collection result callback
1712
2046
  * @return {Promise} returns Promise if no callback passed
1713
2047
  */
1714
2048
  Collection.prototype.stats = function(options, callback) {
@@ -1726,7 +2060,7 @@ Collection.prototype.stats = function(options, callback) {
1726
2060
  return new this.s.promiseLibrary(function(resolve, reject) {
1727
2061
  stats(self, options, function(err, r) {
1728
2062
  if(err) return reject(err);
1729
- resolve(r);
2063
+ resolve(r);
1730
2064
  });
1731
2065
  });
1732
2066
  }
@@ -1744,9 +2078,25 @@ var stats = function(self, options, callback) {
1744
2078
  options = getReadPreference(self, options, self.s.db, self);
1745
2079
 
1746
2080
  // Execute the command
1747
- self.s.db.command(commandObject, options, callback);
2081
+ self.s.db.command(commandObject, options, callback);
1748
2082
  }
1749
2083
 
2084
+ define.classMethod('stats', {callback: true, promise:true});
2085
+
2086
+ /**
2087
+ * @typedef {Object} Collection~findAndModifyWriteOpResult
2088
+ * @property {object} value Document returned from findAndModify command.
2089
+ * @property {object} lastErrorObject The raw lastErrorObject returned from the command.
2090
+ * @property {Number} ok Is 1 if the command executed correctly.
2091
+ */
2092
+
2093
+ /**
2094
+ * The callback format for inserts
2095
+ * @callback Collection~findAndModifyCallback
2096
+ * @param {MongoError} error An error instance representing the error during the execution.
2097
+ * @param {Collection~findAndModifyWriteOpResult} result The result object if the command was executed successfully.
2098
+ */
2099
+
1750
2100
  /**
1751
2101
  * Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation.
1752
2102
  *
@@ -1756,38 +2106,45 @@ var stats = function(self, options, callback) {
1756
2106
  * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
1757
2107
  * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
1758
2108
  * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
1759
- * @param {Collection~resultCallback} callback The collection result callback
2109
+ * @param {Collection~findAndModifyCallback} [callback] The collection result callback
1760
2110
  * @return {Promise} returns Promise if no callback passed
1761
2111
  */
1762
2112
  Collection.prototype.findOneAndDelete = function(filter, options, callback) {
1763
2113
  var self = this;
1764
2114
  if(typeof options == 'function') callback = options, options = {};
2115
+ options = options || {};
1765
2116
 
1766
2117
  // Execute using callback
1767
2118
  if(typeof callback == 'function') return findOneAndDelete(self, filter, options, callback);
1768
2119
 
1769
2120
  // Return a Promise
1770
2121
  return new this.s.promiseLibrary(function(resolve, reject) {
2122
+ options = options || {};
2123
+
1771
2124
  findOneAndDelete(self, filter, options, function(err, r) {
1772
2125
  if(err) return reject(err);
1773
- resolve(r);
2126
+ resolve(r);
1774
2127
  });
1775
2128
  });
1776
2129
  }
1777
2130
 
1778
2131
  var findOneAndDelete = function(self, filter, options, callback) {
2132
+ // Final options
2133
+ var finalOptions = shallowClone(options);
2134
+ finalOptions['fields'] = options.projection;
2135
+ finalOptions['remove'] = true;
2136
+ // Execute find and Modify
1779
2137
  self.findAndModify(
1780
2138
  filter
1781
2139
  , options.sort
1782
2140
  , null
1783
- , {
1784
- fields: options.projection
1785
- , remove:true
1786
- }
2141
+ , finalOptions
1787
2142
  , callback
1788
- );
2143
+ );
1789
2144
  }
1790
2145
 
2146
+ define.classMethod('findOneAndDelete', {callback: true, promise:true});
2147
+
1791
2148
  /**
1792
2149
  * Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation.
1793
2150
  *
@@ -1800,40 +2157,48 @@ var findOneAndDelete = function(self, filter, options, callback) {
1800
2157
  * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
1801
2158
  * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
1802
2159
  * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
1803
- * @param {Collection~resultCallback} callback The collection result callback
2160
+ * @param {Collection~findAndModifyCallback} [callback] The collection result callback
1804
2161
  * @return {Promise} returns Promise if no callback passed
1805
2162
  */
1806
2163
  Collection.prototype.findOneAndReplace = function(filter, replacement, options, callback) {
1807
2164
  var self = this;
1808
2165
  if(typeof options == 'function') callback = options, options = {};
2166
+ options = options || {};
1809
2167
 
1810
2168
  // Execute using callback
1811
2169
  if(typeof callback == 'function') return findOneAndReplace(self, filter, replacement, options, callback);
1812
2170
 
1813
2171
  // Return a Promise
1814
2172
  return new this.s.promiseLibrary(function(resolve, reject) {
2173
+ options = options || {};
2174
+
1815
2175
  findOneAndReplace(self, filter, replacement, options, function(err, r) {
1816
2176
  if(err) return reject(err);
1817
- resolve(r);
2177
+ resolve(r);
1818
2178
  });
1819
2179
  });
1820
2180
  }
1821
2181
 
1822
2182
  var findOneAndReplace = function(self, filter, replacement, options, callback) {
2183
+ // Final options
2184
+ var finalOptions = shallowClone(options);
2185
+ finalOptions['fields'] = options.projection;
2186
+ finalOptions['update'] = true;
2187
+ finalOptions['new'] = typeof options.returnOriginal == 'boolean' ? !options.returnOriginal : false;
2188
+ finalOptions['upsert'] = typeof options.upsert == 'boolean' ? options.upsert : false;
2189
+
2190
+ // Execute findAndModify
1823
2191
  self.findAndModify(
1824
2192
  filter
1825
2193
  , options.sort
1826
2194
  , replacement
1827
- , {
1828
- fields: options.projection
1829
- , update: true
1830
- , new: typeof options.returnOriginal == 'boolean' ? !options.returnOriginal : false
1831
- , upsert: typeof options.upsert == 'boolean' ? options.upsert : false
1832
- }
2195
+ , finalOptions
1833
2196
  , callback
1834
- );
2197
+ );
1835
2198
  }
1836
2199
 
2200
+ define.classMethod('findOneAndReplace', {callback: true, promise:true});
2201
+
1837
2202
  /**
1838
2203
  * Find a document and update it in one atomic operation, requires a write lock for the duration of the operation.
1839
2204
  *
@@ -1846,40 +2211,48 @@ var findOneAndReplace = function(self, filter, replacement, options, callback) {
1846
2211
  * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
1847
2212
  * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
1848
2213
  * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
1849
- * @param {Collection~resultCallback} callback The collection result callback
2214
+ * @param {Collection~findAndModifyCallback} [callback] The collection result callback
1850
2215
  * @return {Promise} returns Promise if no callback passed
1851
2216
  */
1852
2217
  Collection.prototype.findOneAndUpdate = function(filter, update, options, callback) {
1853
2218
  var self = this;
1854
2219
  if(typeof options == 'function') callback = options, options = {};
2220
+ options = options || {};
1855
2221
 
1856
2222
  // Execute using callback
1857
2223
  if(typeof callback == 'function') return findOneAndUpdate(self, filter, update, options, callback);
1858
2224
 
1859
2225
  // Return a Promise
1860
2226
  return new this.s.promiseLibrary(function(resolve, reject) {
2227
+ options = options || {};
2228
+
1861
2229
  findOneAndUpdate(self, filter, update, options, function(err, r) {
1862
2230
  if(err) return reject(err);
1863
- resolve(r);
2231
+ resolve(r);
1864
2232
  });
1865
2233
  });
1866
2234
  }
1867
2235
 
1868
2236
  var findOneAndUpdate = function(self, filter, update, options, callback) {
2237
+ // Final options
2238
+ var finalOptions = shallowClone(options);
2239
+ finalOptions['fields'] = options.projection;
2240
+ finalOptions['update'] = true;
2241
+ finalOptions['new'] = typeof options.returnOriginal == 'boolean' ? !options.returnOriginal : false;
2242
+ finalOptions['upsert'] = typeof options.upsert == 'boolean' ? options.upsert : false;
2243
+
2244
+ // Execute findAndModify
1869
2245
  self.findAndModify(
1870
2246
  filter
1871
2247
  , options.sort
1872
2248
  , update
1873
- , {
1874
- fields: options.projection
1875
- , update: true
1876
- , new: typeof options.returnOriginal == 'boolean' ? !options.returnOriginal : false
1877
- , upsert: typeof options.upsert == 'boolean' ? options.upsert : false
1878
- }
2249
+ , finalOptions
1879
2250
  , callback
1880
- );
2251
+ );
1881
2252
  }
1882
2253
 
2254
+ define.classMethod('findOneAndUpdate', {callback: true, promise:true});
2255
+
1883
2256
  /**
1884
2257
  * Find and update a document.
1885
2258
  * @method
@@ -1894,9 +2267,9 @@ var findOneAndUpdate = function(self, filter, update, options, callback) {
1894
2267
  * @param {boolean} [options.upsert=false] Perform an upsert operation.
1895
2268
  * @param {boolean} [options.new=false] Set to true if you want to return the modified object rather than the original. Ignored for remove.
1896
2269
  * @param {object} [options.fields=null] Object containing the field projection for the result returned from the operation.
1897
- * @param {Collection~resultCallback} callback The command result callback
2270
+ * @param {Collection~resultCallback} [callback] The command result callback
1898
2271
  * @return {Promise} returns Promise if no callback passed
1899
- * @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
2272
+ * @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
1900
2273
  */
1901
2274
  Collection.prototype.findAndModify = function(query, sort, doc, options, callback) {
1902
2275
  var self = this;
@@ -1917,9 +2290,11 @@ Collection.prototype.findAndModify = function(query, sort, doc, options, callbac
1917
2290
 
1918
2291
  // Return a Promise
1919
2292
  return new this.s.promiseLibrary(function(resolve, reject) {
2293
+ options = options || {};
2294
+
1920
2295
  findAndModify(self, query, sort, doc, options, function(err, r) {
1921
2296
  if(err) return reject(err);
1922
- resolve(r);
2297
+ resolve(r);
1923
2298
  });
1924
2299
  });
1925
2300
  }
@@ -1959,14 +2334,29 @@ var findAndModify = function(self, query, sort, doc, options, callback) {
1959
2334
  // No check on the documents
1960
2335
  options.checkKeys = false;
1961
2336
 
2337
+ // Get the write concern settings
2338
+ var finalOptions = writeConcern(options, self.s.db, self, options);
2339
+
2340
+ // Decorate the findAndModify command with the write Concern
2341
+ if(finalOptions.writeConcern) {
2342
+ queryObject.writeConcern = finalOptions.writeConcern;
2343
+ }
2344
+
2345
+ // Have we specified bypassDocumentValidation
2346
+ if(typeof finalOptions.bypassDocumentValidation == 'boolean') {
2347
+ queryObject.bypassDocumentValidation = finalOptions.bypassDocumentValidation;
2348
+ }
2349
+
1962
2350
  // Execute the command
1963
2351
  self.s.db.command(queryObject
1964
2352
  , options, function(err, result) {
1965
2353
  if(err) return handleCallback(callback, err, null);
1966
2354
  return handleCallback(callback, null, result);
1967
- });
2355
+ });
1968
2356
  }
1969
2357
 
2358
+ define.classMethod('findAndModify', {callback: true, promise:true});
2359
+
1970
2360
  /**
1971
2361
  * Find and remove a document.
1972
2362
  * @method
@@ -1976,7 +2366,7 @@ var findAndModify = function(self, query, sort, doc, options, callback) {
1976
2366
  * @param {(number|string)} [options.w=null] The write concern.
1977
2367
  * @param {number} [options.wtimeout=null] The write concern timeout.
1978
2368
  * @param {boolean} [options.j=false] Specify a journal write concern.
1979
- * @param {Collection~resultCallback} callback The command result callback
2369
+ * @param {Collection~resultCallback} [callback] The command result callback
1980
2370
  * @return {Promise} returns Promise if no callback passed
1981
2371
  * @deprecated use findOneAndDelete instead
1982
2372
  */
@@ -1995,7 +2385,7 @@ Collection.prototype.findAndRemove = function(query, sort, options, callback) {
1995
2385
  return new this.s.promiseLibrary(function(resolve, reject) {
1996
2386
  findAndRemove(self, query, sort, options, function(err, r) {
1997
2387
  if(err) return reject(err);
1998
- resolve(r);
2388
+ resolve(r);
1999
2389
  });
2000
2390
  });
2001
2391
  }
@@ -2007,6 +2397,8 @@ var findAndRemove = function(self, query, sort, options, callback) {
2007
2397
  self.findAndModify(query, sort, null, options, callback);
2008
2398
  }
2009
2399
 
2400
+ define.classMethod('findAndRemove', {callback: true, promise:true});
2401
+
2010
2402
  /**
2011
2403
  * Execute an aggregation framework pipeline against the collection, needs MongoDB >= 2.2
2012
2404
  * @method
@@ -2018,6 +2410,7 @@ var findAndRemove = function(self, query, sort, options, callback) {
2018
2410
  * @param {boolean} [options.explain=false] Explain returns the aggregation execution plan (requires mongodb 2.6 >).
2019
2411
  * @param {boolean} [options.allowDiskUse=false] allowDiskUse lets the server know if it can use disk to store temporary results for the aggregation (requires mongodb 2.6 >).
2020
2412
  * @param {number} [options.maxTimeMS=null] maxTimeMS specifies a cumulative time limit in milliseconds for processing operations on the cursor. MongoDB interrupts the operation at the earliest following interrupt point.
2413
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
2021
2414
  * @param {Collection~resultCallback} callback The command result callback
2022
2415
  * @return {(null|AggregationCursor)}
2023
2416
  */
@@ -2034,7 +2427,7 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
2034
2427
  // a cursor based aggregation
2035
2428
  if(options == null && callback == null) {
2036
2429
  options = {};
2037
- }
2430
+ }
2038
2431
  } else {
2039
2432
  // Aggregation pipeline passed as arguments on the method
2040
2433
  var args = Array.prototype.slice.call(arguments, 0);
@@ -2043,20 +2436,37 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
2043
2436
  // Get the possible options object
2044
2437
  var opts = args[args.length - 1];
2045
2438
  // If it contains any of the admissible options pop it of the args
2046
- options = opts && (opts.readPreference
2439
+ options = opts && (opts.readPreference
2047
2440
  || opts.explain || opts.cursor || opts.out
2048
2441
  || opts.maxTimeMS || opts.allowDiskUse) ? args.pop() : {};
2049
2442
  // Left over arguments is the pipeline
2050
2443
  pipeline = args;
2051
2444
  }
2052
2445
 
2446
+ // Ignore readConcern option
2447
+ var ignoreReadConcern = false;
2448
+
2053
2449
  // If out was specified
2054
2450
  if(typeof options.out == 'string') {
2055
2451
  pipeline.push({$out: options.out});
2452
+ ignoreReadConcern = true;
2453
+ } else if(pipeline.length > 0 && pipeline[pipeline.length - 1]['$out']) {
2454
+ ignoreReadConcern = true;
2056
2455
  }
2057
2456
 
2058
2457
  // Build the command
2059
2458
  var command = { aggregate : this.s.name, pipeline : pipeline};
2459
+
2460
+ // If we have bypassDocumentValidation set
2461
+ if(typeof options.bypassDocumentValidation == 'boolean') {
2462
+ command.bypassDocumentValidation = options.bypassDocumentValidation;
2463
+ }
2464
+
2465
+ // Do we have a readConcern specified
2466
+ if(!ignoreReadConcern && this.s.readConcern) {
2467
+ command.readConcern = this.s.readConcern;
2468
+ }
2469
+
2060
2470
  // If we have allowDiskUse defined
2061
2471
  if(options.allowDiskUse) command.allowDiskUse = options.allowDiskUse;
2062
2472
  if(typeof options.maxTimeMS == 'number') command.maxTimeMS = options.maxTimeMS;
@@ -2078,9 +2488,13 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
2078
2488
  // Set the AggregationCursor constructor
2079
2489
  options.cursorFactory = AggregationCursor;
2080
2490
  if(typeof callback != 'function') {
2491
+ if(!this.s.topology.capabilities()) {
2492
+ throw new MongoError('cannot connect to server');
2493
+ }
2494
+
2081
2495
  if(this.s.topology.capabilities().hasAggregationCursor) {
2082
2496
  options.cursor = options.cursor || { batchSize : 1000 };
2083
- command.cursor = options.cursor;
2497
+ command.cursor = options.cursor;
2084
2498
  }
2085
2499
 
2086
2500
  // Allow disk usage command
@@ -2113,6 +2527,8 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
2113
2527
  });
2114
2528
  }
2115
2529
 
2530
+ define.classMethod('aggregate', {callback: true, promise:false});
2531
+
2116
2532
  /**
2117
2533
  * The callback format for results
2118
2534
  * @callback Collection~parallelCollectionScanCallback
@@ -2129,7 +2545,7 @@ Collection.prototype.aggregate = function(pipeline, options, callback) {
2129
2545
  * @param {number} [options.batchSize=null] Set the batchSize for the getMoreCommand when iterating over the query results.
2130
2546
  * @param {number} [options.numCursors=1] The maximum number of parallel command cursors to return (the number of returned cursors will be in the range 1:numCursors)
2131
2547
  * @param {boolean} [options.raw=false] Return all BSON documents as Raw Buffer documents.
2132
- * @param {Collection~parallelCollectionScanCallback} callback The command result callback
2548
+ * @param {Collection~parallelCollectionScanCallback} [callback] The command result callback
2133
2549
  * @return {Promise} returns Promise if no callback passed
2134
2550
  */
2135
2551
  Collection.prototype.parallelCollectionScan = function(options, callback) {
@@ -2141,7 +2557,7 @@ Collection.prototype.parallelCollectionScan = function(options, callback) {
2141
2557
 
2142
2558
  // Ensure we have the right read preference inheritance
2143
2559
  options = getReadPreference(this, options, this.s.db, this);
2144
-
2560
+
2145
2561
  // Add a promiseLibrary
2146
2562
  options.promiseLibrary = this.s.promiseLibrary;
2147
2563
 
@@ -2152,7 +2568,7 @@ Collection.prototype.parallelCollectionScan = function(options, callback) {
2152
2568
  return new this.s.promiseLibrary(function(resolve, reject) {
2153
2569
  parallelCollectionScan(self, options, function(err, r) {
2154
2570
  if(err) return reject(err);
2155
- resolve(r);
2571
+ resolve(r);
2156
2572
  });
2157
2573
  });
2158
2574
  }
@@ -2164,6 +2580,11 @@ var parallelCollectionScan = function(self, options, callback) {
2164
2580
  , numCursors: options.numCursors
2165
2581
  }
2166
2582
 
2583
+ // Do we have a readConcern specified
2584
+ if(self.s.readConcern) {
2585
+ commandObject.readConcern = self.s.readConcern;
2586
+ }
2587
+
2167
2588
  // Execute the command
2168
2589
  self.s.db.command(commandObject, options, function(err, result) {
2169
2590
  if(err) return handleCallback(callback, err, null);
@@ -2188,13 +2609,15 @@ var parallelCollectionScan = function(self, options, callback) {
2188
2609
  }
2189
2610
 
2190
2611
  handleCallback(callback, null, cursors);
2191
- });
2612
+ });
2192
2613
  }
2193
2614
 
2615
+ define.classMethod('parallelCollectionScan', {callback: true, promise:true});
2616
+
2194
2617
  /**
2195
2618
  * Execute the geoNear command to search for items in the collection
2196
2619
  *
2197
- * @method
2620
+ * @method
2198
2621
  * @param {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
2199
2622
  * @param {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
2200
2623
  * @param {object} [options=null] Optional settings.
@@ -2206,8 +2629,8 @@ var parallelCollectionScan = function(self, options, callback) {
2206
2629
  * @param {object} [options.query=null] Filter the results by a query.
2207
2630
  * @param {boolean} [options.spherical=false] Perform query using a spherical model.
2208
2631
  * @param {boolean} [options.uniqueDocs=false] The closest location in a document to the center of the search region will always be returned MongoDB > 2.X.
2209
- * @param {boolean} [options.includeLocs=false] Include the location data fields in the top level of the results MongoDB > 2.X.
2210
- * @param {Collection~resultCallback} callback The command result callback
2632
+ * @param {boolean} [options.includeLocs=false] Include the location data fields in the top level of the results MongoDB > 2.X.
2633
+ * @param {Collection~resultCallback} [callback] The command result callback
2211
2634
  * @return {Promise} returns Promise if no callback passed
2212
2635
  */
2213
2636
  Collection.prototype.geoNear = function(x, y, options, callback) {
@@ -2227,7 +2650,7 @@ Collection.prototype.geoNear = function(x, y, options, callback) {
2227
2650
  return new this.s.promiseLibrary(function(resolve, reject) {
2228
2651
  geoNear(self, x, y, point, options, function(err, r) {
2229
2652
  if(err) return reject(err);
2230
- resolve(r);
2653
+ resolve(r);
2231
2654
  });
2232
2655
  });
2233
2656
  }
@@ -2245,14 +2668,19 @@ var geoNear = function(self, x, y, point, options, callback) {
2245
2668
  // Exclude readPreference and existing options to prevent user from
2246
2669
  // shooting themselves in the foot
2247
2670
  var exclude = {
2248
- readPreference: true,
2671
+ readPreference: true,
2249
2672
  geoNear: true,
2250
- near: true
2673
+ near: true
2251
2674
  };
2252
2675
 
2253
2676
  // Filter out any excluded objects
2254
2677
  commandObject = decorateCommand(commandObject, options, exclude);
2255
2678
 
2679
+ // Do we have a readConcern specified
2680
+ if(self.s.readConcern) {
2681
+ commandObject.readConcern = self.s.readConcern;
2682
+ }
2683
+
2256
2684
  // Execute the command
2257
2685
  self.s.db.command(commandObject, options, function (err, res) {
2258
2686
  if(err) return handleCallback(callback, err);
@@ -2260,13 +2688,15 @@ var geoNear = function(self, x, y, point, options, callback) {
2260
2688
  // should we only be returning res.results here? Not sure if the user
2261
2689
  // should see the other return information
2262
2690
  handleCallback(callback, null, res);
2263
- });
2691
+ });
2264
2692
  }
2265
2693
 
2694
+ define.classMethod('geoNear', {callback: true, promise:true});
2695
+
2266
2696
  /**
2267
2697
  * Execute a geo search using a geo haystack index on a collection.
2268
2698
  *
2269
- * @method
2699
+ * @method
2270
2700
  * @param {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
2271
2701
  * @param {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
2272
2702
  * @param {object} [options=null] Optional settings.
@@ -2274,7 +2704,7 @@ var geoNear = function(self, x, y, point, options, callback) {
2274
2704
  * @param {number} [options.maxDistance=null] Include results up to maxDistance from the point.
2275
2705
  * @param {object} [options.search=null] Filter the results by a query.
2276
2706
  * @param {number} [options.limit=false] Max number of results to return.
2277
- * @param {Collection~resultCallback} callback The command result callback
2707
+ * @param {Collection~resultCallback} [callback] The command result callback
2278
2708
  * @return {Promise} returns Promise if no callback passed
2279
2709
  */
2280
2710
  Collection.prototype.geoHaystackSearch = function(x, y, options, callback) {
@@ -2292,7 +2722,7 @@ Collection.prototype.geoHaystackSearch = function(x, y, options, callback) {
2292
2722
  return new this.s.promiseLibrary(function(resolve, reject) {
2293
2723
  geoHaystackSearch(self, x, y, options, function(err, r) {
2294
2724
  if(err) return reject(err);
2295
- resolve(r);
2725
+ resolve(r);
2296
2726
  });
2297
2727
  });
2298
2728
  }
@@ -2310,6 +2740,11 @@ var geoHaystackSearch = function(self, x, y, options, callback) {
2310
2740
  // Ensure we have the right read preference inheritance
2311
2741
  options = getReadPreference(self, options, self.s.db, self);
2312
2742
 
2743
+ // Do we have a readConcern specified
2744
+ if(self.s.readConcern) {
2745
+ commandObject.readConcern = self.s.readConcern;
2746
+ }
2747
+
2313
2748
  // Execute the command
2314
2749
  self.s.db.command(commandObject, options, function (err, res) {
2315
2750
  if(err) return handleCallback(callback, err);
@@ -2317,9 +2752,11 @@ var geoHaystackSearch = function(self, x, y, options, callback) {
2317
2752
  // should we only be returning res.results here? Not sure if the user
2318
2753
  // should see the other return information
2319
2754
  handleCallback(callback, null, res);
2320
- });
2755
+ });
2321
2756
  }
2322
2757
 
2758
+ define.classMethod('geoHaystackSearch', {callback: true, promise:true});
2759
+
2323
2760
  /**
2324
2761
  * Group function helper
2325
2762
  * @ignore
@@ -2355,7 +2792,7 @@ var groupFunction = function () {
2355
2792
  /**
2356
2793
  * Run a group command across a collection
2357
2794
  *
2358
- * @method
2795
+ * @method
2359
2796
  * @param {(object|array|function|code)} keys An object, array or function expressing the keys to group by.
2360
2797
  * @param {object} condition An optional condition that must be true for a row to be considered.
2361
2798
  * @param {object} initial Initial value of the aggregation counter object.
@@ -2364,7 +2801,7 @@ var groupFunction = function () {
2364
2801
  * @param {boolean} command Specify if you wish to run using the internal group command or using eval, default is true.
2365
2802
  * @param {object} [options=null] Optional settings.
2366
2803
  * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2367
- * @param {Collection~resultCallback} callback The command result callback
2804
+ * @param {Collection~resultCallback} [callback] The command result callback
2368
2805
  * @return {Promise} returns Promise if no callback passed
2369
2806
  */
2370
2807
  Collection.prototype.group = function(keys, condition, initial, reduce, finalize, command, options, callback) {
@@ -2406,7 +2843,7 @@ Collection.prototype.group = function(keys, condition, initial, reduce, finalize
2406
2843
  return new this.s.promiseLibrary(function(resolve, reject) {
2407
2844
  group(self, keys, condition, initial, reduce, finalize, command, options, function(err, r) {
2408
2845
  if(err) return reject(err);
2409
- resolve(r);
2846
+ resolve(r);
2410
2847
  });
2411
2848
  });
2412
2849
  }
@@ -2445,6 +2882,12 @@ var group = function(self, keys, condition, initial, reduce, finalize, command,
2445
2882
 
2446
2883
  // Ensure we have the right read preference inheritance
2447
2884
  options = getReadPreference(self, options, self.s.db, self);
2885
+
2886
+ // Do we have a readConcern specified
2887
+ if(self.s.readConcern) {
2888
+ selector.readConcern = self.s.readConcern;
2889
+ }
2890
+
2448
2891
  // Execute command
2449
2892
  self.s.db.command(selector, options, function(err, result) {
2450
2893
  if(err) return handleCallback(callback, err, null);
@@ -2468,9 +2911,11 @@ var group = function(self, keys, condition, initial, reduce, finalize, command,
2468
2911
  if (err) return handleCallback(callback, err, null);
2469
2912
  handleCallback(callback, null, results.result || results);
2470
2913
  });
2471
- }
2914
+ }
2472
2915
  }
2473
2916
 
2917
+ define.classMethod('group', {callback: true, promise:true});
2918
+
2474
2919
  /**
2475
2920
  * Functions that are passed as scope args must
2476
2921
  * be converted to Code instances.
@@ -2501,7 +2946,7 @@ function processScope (scope) {
2501
2946
  /**
2502
2947
  * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
2503
2948
  *
2504
- * @method
2949
+ * @method
2505
2950
  * @param {(function|string)} map The mapping function.
2506
2951
  * @param {(function|string)} reduce The reduce function.
2507
2952
  * @param {object} [options=null] Optional settings.
@@ -2515,7 +2960,8 @@ function processScope (scope) {
2515
2960
  * @param {object} [options.scope=null] Can pass in variables that can be access from map/reduce/finalize.
2516
2961
  * @param {boolean} [options.jsMode=false] It is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X.
2517
2962
  * @param {boolean} [options.verbose=false] Provide statistics on job execution time.
2518
- * @param {Collection~resultCallback} callback The command result callback
2963
+ * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
2964
+ * @param {Collection~resultCallback} [callback] The command result callback
2519
2965
  * @throws {MongoError}
2520
2966
  * @return {Promise} returns Promise if no callback passed
2521
2967
  */
@@ -2547,7 +2993,7 @@ Collection.prototype.mapReduce = function(map, reduce, options, callback) {
2547
2993
  mapReduce(self, map, reduce, options, function(err, r, r1) {
2548
2994
  if(err) return reject(err);
2549
2995
  if(r instanceof Collection) return resolve(r);
2550
- resolve({results: r, stats: r1});
2996
+ resolve({results: r, stats: r1});
2551
2997
  });
2552
2998
  });
2553
2999
  }
@@ -2572,9 +3018,16 @@ var mapReduce = function(self, map, reduce, options, callback) {
2572
3018
  options = getReadPreference(self, options, self.s.db, self);
2573
3019
 
2574
3020
  // If we have a read preference and inline is not set as output fail hard
2575
- if((options.readPreference != false && options.readPreference != 'primary')
3021
+ if((options.readPreference != false && options.readPreference != 'primary')
2576
3022
  && options['out'] && (options['out'].inline != 1 && options['out'] != 'inline')) {
2577
- options.readPreference = 'primary';
3023
+ options.readPreference = 'primary';
3024
+ } else if(self.s.readConcern) {
3025
+ mapCommandHash.readConcern = self.s.readConcern;
3026
+ }
3027
+
3028
+ // Is bypassDocumentValidation specified
3029
+ if(typeof options.bypassDocumentValidation == 'boolean') {
3030
+ mapCommandHash.bypassDocumentValidation = options.bypassDocumentValidation;
2578
3031
  }
2579
3032
 
2580
3033
  // Execute command
@@ -2597,7 +3050,7 @@ var mapReduce = function(self, map, reduce, options, callback) {
2597
3050
  if(options['verbose'] == null || !options['verbose']) {
2598
3051
  return handleCallback(callback, null, result.results);
2599
3052
  }
2600
-
3053
+
2601
3054
  return handleCallback(callback, null, result.results, stats);
2602
3055
  }
2603
3056
 
@@ -2623,10 +3076,12 @@ var mapReduce = function(self, map, reduce, options, callback) {
2623
3076
  });
2624
3077
  }
2625
3078
 
3079
+ define.classMethod('mapReduce', {callback: true, promise:true});
3080
+
2626
3081
  /**
2627
3082
  * Initiate a Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order.
2628
3083
  *
2629
- * @method
3084
+ * @method
2630
3085
  * @param {object} [options=null] Optional settings.
2631
3086
  * @param {(number|string)} [options.w=null] The write concern.
2632
3087
  * @param {number} [options.wtimeout=null] The write concern timeout.
@@ -2639,10 +3094,12 @@ Collection.prototype.initializeUnorderedBulkOp = function(options) {
2639
3094
  return unordered(this.s.topology, this, options);
2640
3095
  }
2641
3096
 
3097
+ define.classMethod('initializeUnorderedBulkOp', {callback: false, promise:false, returns: [ordered.UnorderedBulkOperation]});
3098
+
2642
3099
  /**
2643
3100
  * Initiate an In order bulk write operation, operations will be serially executed in the order they are added, creating a new operation for each switch in types.
2644
3101
  *
2645
- * @method
3102
+ * @method
2646
3103
  * @param {object} [options=null] Optional settings.
2647
3104
  * @param {(number|string)} [options.w=null] The write concern.
2648
3105
  * @param {number} [options.wtimeout=null] The write concern timeout.
@@ -2656,6 +3113,8 @@ Collection.prototype.initializeOrderedBulkOp = function(options) {
2656
3113
  return ordered(this.s.topology, this, options);
2657
3114
  }
2658
3115
 
3116
+ define.classMethod('initializeOrderedBulkOp', {callback: false, promise:false, returns: [ordered.OrderedBulkOperation]});
3117
+
2659
3118
  // Get write concern
2660
3119
  var writeConcern = function(target, db, col, options) {
2661
3120
  if(options.w != null || options.j != null || options.fsync != null) {
@@ -2665,7 +3124,7 @@ var writeConcern = function(target, db, col, options) {
2665
3124
  if(options.j != null) opts.j = options.j;
2666
3125
  if(options.fsync != null) opts.fsync = options.fsync;
2667
3126
  target.writeConcern = opts;
2668
- } else if(col.writeConcern.w != null || col.writeConcern.j != null || col.writeConcern.fsync != null) {
3127
+ } else if(col.writeConcern.w != null || col.writeConcern.j != null || col.writeConcern.fsync != null) {
2669
3128
  target.writeConcern = col.writeConcern;
2670
3129
  } else if(db.writeConcern.w != null || db.writeConcern.j != null || db.writeConcern.fsync != null) {
2671
3130
  target.writeConcern = db.writeConcern;
@@ -2685,7 +3144,7 @@ var getReadPreference = function(self, options, db, coll) {
2685
3144
  r = db.readPreference;
2686
3145
  }
2687
3146
 
2688
- if(r instanceof ReadPreference) {
3147
+ if(r instanceof ReadPreference) {
2689
3148
  options.readPreference = new CoreReadPreference(r.mode, r.tags);
2690
3149
  } else if(typeof r == 'string') {
2691
3150
  options.readPreference = new CoreReadPreference(r);