3 var checkCollectionName = require('./utils').checkCollectionName
4 , ObjectID = require('mongodb-core').BSON.ObjectID
5 , Long = require('mongodb-core').BSON.Long
6 , Code = require('mongodb-core').BSON.Code
7 , f = require('util').format
8 , AggregationCursor = require('./aggregation_cursor')
9 , MongoError = require('mongodb-core').MongoError
10 , shallowClone = require('./utils').shallowClone
11 , isObject = require('./utils').isObject
12 , toError = require('./utils').toError
13 , normalizeHintField = require('./utils').normalizeHintField
14 , handleCallback = require('./utils').handleCallback
15 , decorateCommand = require('./utils').decorateCommand
16 , formattedOrderClause = require('./utils').formattedOrderClause
17 , ReadPreference = require('./read_preference')
18 , CoreReadPreference = require('mongodb-core').ReadPreference
19 , CommandCursor = require('./command_cursor')
20 , Define = require('./metadata')
21 , Cursor = require('./cursor')
22 , unordered = require('./bulk/unordered')
23 , ordered = require('./bulk/ordered')
24 , assign = require('./utils').assign;
27 * @fileOverview The **Collection** class is an internal class that embodies a MongoDB collection
28 * allowing for insert/update/remove/find and other command operation on that MongoDB collection.
30 * **COLLECTION Cannot directly be instantiated**
32 * var MongoClient = require('mongodb').MongoClient,
33 * test = require('assert');
35 * var url = 'mongodb://localhost:27017/test';
36 * // Connect using MongoClient
37 * MongoClient.connect(url, function(err, db) {
38 * // Create a collection we want to drop later
39 * var col = db.collection('createIndexExample1');
40 * // Show that duplicate records got dropped
41 * col.find({}).toArray(function(err, items) {
42 * test.equal(null, err);
43 * test.equal(4, items.length);
50 * Create a new Collection instance (INTERNAL TYPE, do not instantiate directly)
52 * @property {string} collectionName Get the collection name.
53 * @property {string} namespace Get the full collection namespace.
54 * @property {object} writeConcern The current write concern values.
55 * @property {object} readConcern The current read concern values.
56 * @property {object} hint Get current index hint for collection.
57 * @return {Collection} a Collection instance.
59 var Collection = function(db, topology, dbName, name, pkFactory, options) {
60 checkCollectionName(name);
63 var internalHint = null;
64 var opts = options != null && ('object' === typeof options) ? options : {};
65 var slaveOk = options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk;
66 var serializeFunctions = options == null || options.serializeFunctions == null ? db.s.options.serializeFunctions : options.serializeFunctions;
67 var raw = options == null || options.raw == null ? db.s.options.raw : options.raw;
68 var promoteLongs = options == null || options.promoteLongs == null ? db.s.options.promoteLongs : options.promoteLongs;
69 var promoteValues = options == null || options.promoteValues == null ? db.s.options.promoteValues : options.promoteValues;
70 var promoteBuffers = options == null || options.promoteBuffers == null ? db.s.options.promoteBuffers : options.promoteBuffers;
71 var readPreference = null;
72 var collectionHint = null;
73 var namespace = f("%s.%s", dbName, name);
75 // Get the promiseLibrary
76 var promiseLibrary = options.promiseLibrary;
78 // No promise library selected fall back
80 promiseLibrary = typeof global.Promise == 'function' ?
81 global.Promise : require('es6-promise').Promise;
84 // Assign the right collection level readPreference
85 if(options && options.readPreference) {
86 readPreference = options.readPreference;
87 } else if(db.options.readPreference) {
88 readPreference = db.options.readPreference;
91 // Set custom primary key factory if provided
92 pkFactory = pkFactory == null
98 // Set custom primary key factory if provided
109 , namespace: namespace
111 , readPreference: readPreference
114 // Serialize functions
115 , serializeFunctions: serializeFunctions
119 , promoteLongs: promoteLongs
121 , promoteValues: promoteValues
123 , promoteBuffers: promoteBuffers
125 , internalHint: internalHint
127 , collectionHint: collectionHint
131 , promiseLibrary: promiseLibrary
133 , readConcern: options.readConcern
137 var define = Collection.define = new Define('Collection', Collection, false);
139 Object.defineProperty(Collection.prototype, 'collectionName', {
140 enumerable: true, get: function() { return this.s.name; }
143 Object.defineProperty(Collection.prototype, 'namespace', {
144 enumerable: true, get: function() { return this.s.namespace; }
147 Object.defineProperty(Collection.prototype, 'readConcern', {
148 enumerable: true, get: function() { return this.s.readConcern || {level: 'local'}; }
151 Object.defineProperty(Collection.prototype, 'writeConcern', {
155 if(this.s.options.w != null) ops.w = this.s.options.w;
156 if(this.s.options.j != null) ops.j = this.s.options.j;
157 if(this.s.options.fsync != null) ops.fsync = this.s.options.fsync;
158 if(this.s.options.wtimeout != null) ops.wtimeout = this.s.options.wtimeout;
166 Object.defineProperty(Collection.prototype, "hint", {
168 , get: function () { return this.s.collectionHint; }
169 , set: function (v) { this.s.collectionHint = normalizeHintField(v); }
173 * Creates a cursor for a query that can be used to iterate over results from MongoDB
175 * @param {object} query The cursor query object.
176 * @throws {MongoError}
179 Collection.prototype.find = function() {
181 , args = Array.prototype.slice.call(arguments, 0)
182 , has_callback = typeof args[args.length - 1] === 'function'
183 , has_weird_callback = typeof args[0] === 'function'
184 , callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null)
186 , selector = len >= 1 ? args[0] : {}
187 , fields = len >= 2 ? args[1] : undefined;
189 if(len === 1 && has_weird_callback) {
190 // backwards compat for callback?, options case
195 if(len === 2 && fields !== undefined && !Array.isArray(fields)) {
196 var fieldKeys = Object.keys(fields);
197 var is_option = false;
199 for(var i = 0; i < fieldKeys.length; i++) {
200 if(testForFields[fieldKeys[i]] != null) {
212 } else if(len === 2 && Array.isArray(fields) && !Array.isArray(fields[0])) {
215 for(var i = 0; i < fields.length; i++) {
216 newFields[fields[i]] = 1;
226 // Ensure selector is not null
227 selector = selector == null ? {} : selector;
228 // Validate correctness off the selector
229 var object = selector;
230 if(Buffer.isBuffer(object)) {
231 var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
232 if(object_size != object.length) {
233 var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
234 error.name = 'MongoError';
239 // Validate correctness of the field selector
241 if(Buffer.isBuffer(object)) {
242 var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
243 if(object_size != object.length) {
244 var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
245 error.name = 'MongoError';
250 // Check special case where we are using an objectId
251 if(selector instanceof ObjectID || (selector != null && selector._bsontype == 'ObjectID')) {
252 selector = {_id:selector};
255 // If it's a serialized fields field we need to just let it through
256 // user be warned it better be good
257 if(options && options.fields && !(Buffer.isBuffer(options.fields))) {
260 if(Array.isArray(options.fields)) {
261 if(!options.fields.length) {
264 for (var i = 0, l = options.fields.length; i < l; i++) {
265 fields[options.fields[i]] = 1;
269 fields = options.fields;
273 if (!options) options = {};
276 // Make a shallow copy of options
277 for (var key in options) {
278 newOptions[key] = options[key];
282 newOptions.skip = len > 3 ? args[2] : options.skip ? options.skip : 0;
283 newOptions.limit = len > 3 ? args[3] : options.limit ? options.limit : 0;
284 newOptions.raw = options.raw != null && typeof options.raw === 'boolean' ? options.raw : this.s.raw;
285 newOptions.hint = options.hint != null ? normalizeHintField(options.hint) : this.s.collectionHint;
286 newOptions.timeout = len == 5 ? args[4] : typeof options.timeout === 'undefined' ? undefined : options.timeout;
287 // // If we have overridden slaveOk otherwise use the default db setting
288 newOptions.slaveOk = options.slaveOk != null ? options.slaveOk : this.s.db.slaveOk;
290 // Add read preference if needed
291 newOptions = getReadPreference(this, newOptions, this.s.db, this);
293 // Set slave ok to true if read preference different from primary
294 if(newOptions.readPreference != null
295 && (newOptions.readPreference != 'primary' || newOptions.readPreference.mode != 'primary')) {
296 newOptions.slaveOk = true;
299 // Ensure the query is an object
300 if(selector != null && typeof selector != 'object') {
301 throw MongoError.create({message: "query selector must be an object", driver:true });
304 // Build the find command
306 find: this.s.namespace
307 , limit: newOptions.limit
308 , skip: newOptions.skip
312 // Ensure we use the right await data option
313 if(typeof newOptions.awaitdata == 'boolean') {
314 newOptions.awaitData = newOptions.awaitdata
317 // Translate to new command option noCursorTimeout
318 if(typeof newOptions.timeout == 'boolean') newOptions.noCursorTimeout = newOptions.timeout;
320 // Merge in options to command
321 for(var name in newOptions) {
322 if(newOptions[name] != null) findCommand[name] = newOptions[name];
326 var formatFields = function(fields) {
328 if(Array.isArray(fields)) {
329 for(var i = 0; i < fields.length; i++) {
330 if(Array.isArray(fields[i])) {
331 object[fields[i][0]] = fields[i][1];
333 object[fields[i][0]] = 1;
343 // Special treatment for the fields selector
344 if(fields) findCommand.fields = formatFields(fields);
346 // Add db object to the new options
347 newOptions.db = this.s.db;
349 // Add the promise library
350 newOptions.promiseLibrary = this.s.promiseLibrary;
352 // Set raw if available at collection level
353 if(newOptions.raw == null && typeof this.s.raw == 'boolean') newOptions.raw = this.s.raw;
354 // Set promoteLongs if available at collection level
355 if(newOptions.promoteLongs == null && typeof this.s.promoteLongs == 'boolean') newOptions.promoteLongs = this.s.promoteLongs;
356 if(newOptions.promoteValues == null && typeof this.s.promoteValues == 'boolean') newOptions.promoteValues = this.s.promoteValues;
357 if(newOptions.promoteBuffers == null && typeof this.s.promoteBuffers == 'boolean') newOptions.promoteBuffers = this.s.promoteBuffers;
360 if(findCommand.sort) {
361 findCommand.sort = formattedOrderClause(findCommand.sort);
364 // Set the readConcern
365 if(this.s.readConcern) {
366 findCommand.readConcern = this.s.readConcern;
369 // Decorate find command with collation options
370 decorateWithCollation(findCommand, this, options);
373 if(typeof callback == 'function') return handleCallback(callback, null, this.s.topology.cursor(this.s.namespace, findCommand, newOptions));
374 return this.s.topology.cursor(this.s.namespace, findCommand, newOptions);
377 define.classMethod('find', {callback: false, promise:false, returns: [Cursor]});
380 * Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,
381 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
382 * can be overridden by setting the **forceServerObjectId** flag.
385 * @param {object} doc Document to insert.
386 * @param {object} [options=null] Optional settings.
387 * @param {(number|string)} [options.w=null] The write concern.
388 * @param {number} [options.wtimeout=null] The write concern timeout.
389 * @param {boolean} [options.j=false] Specify a journal write concern.
390 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
391 * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
392 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
393 * @param {Collection~insertOneWriteOpCallback} [callback] The command result callback
394 * @return {Promise} returns Promise if no callback passed
396 Collection.prototype.insertOne = function(doc, options, callback) {
398 if(typeof options == 'function') callback = options, options = {};
399 options = options || {};
400 if(Array.isArray(doc) && typeof callback == 'function') {
401 return callback(MongoError.create({message: 'doc parameter must be an object', driver:true }));
402 } else if(Array.isArray(doc)) {
403 return new this.s.promiseLibrary(function(resolve, reject) {
404 reject(MongoError.create({message: 'doc parameter must be an object', driver:true }));
408 // Add ignoreUndfined
409 if(this.s.options.ignoreUndefined) {
410 options = shallowClone(options);
411 options.ignoreUndefined = this.s.options.ignoreUndefined;
414 // Execute using callback
415 if(typeof callback == 'function') return insertOne(self, doc, options, callback);
418 return new this.s.promiseLibrary(function(resolve, reject) {
419 insertOne(self, doc, options, function(err, r) {
420 if(err) return reject(err);
426 var insertOne = function(self, doc, options, callback) {
427 insertDocuments(self, [doc], options, function(err, r) {
428 if(callback == null) return;
429 if(err && callback) return callback(err);
430 // Workaround for pre 2.6 servers
431 if(r == null) return callback(null, {result: {ok:1}});
432 // Add values to top level to ensure crud spec compatibility
433 r.insertedCount = r.result.n;
434 r.insertedId = doc._id;
435 if(callback) callback(null, r);
439 var mapInserManyResults = function(docs, r) {
440 var ids = r.getInsertedIds();
441 var keys = Object.keys(ids);
442 var finalIds = new Array(keys.length);
444 for(var i = 0; i < keys.length; i++) {
445 if(ids[keys[i]]._id) {
446 finalIds[ids[keys[i]].index] = ids[keys[i]]._id;
451 result: {ok: 1, n: r.insertedCount},
453 insertedCount: r.insertedCount,
454 insertedIds: finalIds
458 finalResult.result.opTime = r.getLastOp();
464 define.classMethod('insertOne', {callback: true, promise:true});
467 * Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
468 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
469 * can be overridden by setting the **forceServerObjectId** flag.
472 * @param {object[]} docs Documents to insert.
473 * @param {object} [options=null] Optional settings.
474 * @param {(number|string)} [options.w=null] The write concern.
475 * @param {number} [options.wtimeout=null] The write concern timeout.
476 * @param {boolean} [options.j=false] Specify a journal write concern.
477 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
478 * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
479 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
480 * @param {Collection~insertWriteOpCallback} [callback] The command result callback
481 * @return {Promise} returns Promise if no callback passed
483 Collection.prototype.insertMany = function(docs, options, callback) {
485 if(typeof options == 'function') callback = options, options = {};
486 options = options || {ordered:true};
487 if(!Array.isArray(docs) && typeof callback == 'function') {
488 return callback(MongoError.create({message: 'docs parameter must be an array of documents', driver:true }));
489 } else if(!Array.isArray(docs)) {
490 return new this.s.promiseLibrary(function(resolve, reject) {
491 reject(MongoError.create({message: 'docs parameter must be an array of documents', driver:true }));
495 // Get the write concern options
496 if(typeof options.checkKeys != 'boolean') {
497 options.checkKeys = true;
500 // If keep going set unordered
501 options['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
503 // Set up the force server object id
504 var forceServerObjectId = typeof options.forceServerObjectId == 'boolean'
505 ? options.forceServerObjectId : self.s.db.options.forceServerObjectId;
507 // Do we want to force the server to assign the _id key
508 if(forceServerObjectId !== true) {
509 // Add _id if not specified
510 for(var i = 0; i < docs.length; i++) {
511 if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
515 // Generate the bulk write operations
520 // Execute using callback
521 if(typeof callback == 'function') return bulkWrite(self, operations, options, function(err, r) {
522 if(err) return callback(err, r);
523 callback(null, mapInserManyResults(docs, r));
527 return new this.s.promiseLibrary(function(resolve, reject) {
528 bulkWrite(self, operations, options, function(err, r) {
529 if(err) return reject(err);
530 resolve(mapInserManyResults(docs, r));
535 define.classMethod('insertMany', {callback: true, promise:true});
538 * @typedef {Object} Collection~BulkWriteOpResult
539 * @property {number} insertedCount Number of documents inserted.
540 * @property {number} matchedCount Number of documents matched for update.
541 * @property {number} modifiedCount Number of documents modified.
542 * @property {number} deletedCount Number of documents deleted.
543 * @property {number} upsertedCount Number of documents upserted.
544 * @property {object} insertedIds Inserted document generated Id's, hash key is the index of the originating operation
545 * @property {object} upsertedIds Upserted document generated Id's, hash key is the index of the originating operation
546 * @property {object} result The command result object.
550 * The callback format for inserts
551 * @callback Collection~bulkWriteOpCallback
552 * @param {MongoError} error An error instance representing the error during the execution.
553 * @param {Collection~BulkWriteOpResult} result The result object if the command was executed successfully.
557 * Perform a bulkWrite operation without a fluent API
559 * Legal operation types are
561 * { insertOne: { document: { a: 1 } } }
563 * { updateOne: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
565 * { updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
567 * { deleteOne: { filter: {c:1} } }
569 * { deleteMany: { filter: {c:1} } }
571 * { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}
573 * If documents passed in do not contain the **_id** field,
574 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
575 * can be overridden by setting the **forceServerObjectId** flag.
578 * @param {object[]} operations Bulk operations to perform.
579 * @param {object} [options=null] Optional settings.
580 * @param {(number|string)} [options.w=null] The write concern.
581 * @param {number} [options.wtimeout=null] The write concern timeout.
582 * @param {boolean} [options.j=false] Specify a journal write concern.
583 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
584 * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
585 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
586 * @param {Collection~bulkWriteOpCallback} [callback] The command result callback
587 * @return {Promise} returns Promise if no callback passed
589 Collection.prototype.bulkWrite = function(operations, options, callback) {
591 if(typeof options == 'function') callback = options, options = {};
592 options = options || {ordered:true};
594 if(!Array.isArray(operations)) {
595 throw MongoError.create({message: "operations must be an array of documents", driver:true });
598 // Execute using callback
599 if(typeof callback == 'function') return bulkWrite(self, operations, options, callback);
602 return new this.s.promiseLibrary(function(resolve, reject) {
603 bulkWrite(self, operations, options, function(err, r) {
604 if(err && r == null) return reject(err);
610 var bulkWrite = function(self, operations, options, callback) {
611 // Add ignoreUndfined
612 if(self.s.options.ignoreUndefined) {
613 options = shallowClone(options);
614 options.ignoreUndefined = self.s.options.ignoreUndefined;
617 // Create the bulk operation
618 var bulk = options.ordered == true || options.ordered == null ? self.initializeOrderedBulkOp(options) : self.initializeUnorderedBulkOp(options);
620 // Do we have a collation
621 var collation = false;
623 // for each op go through and add to the bulk
625 for(var i = 0; i < operations.length; i++) {
626 // Get the operation type
627 var key = Object.keys(operations[i])[0];
628 // Check if we have a collation
629 if(operations[i][key].collation) {
633 // Pass to the raw bulk
634 bulk.raw(operations[i]);
637 return callback(err, null);
640 // Final options for write concern
641 var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
642 var writeCon = finalOptions.writeConcern ? finalOptions.writeConcern : {};
643 var capabilities = self.s.topology.capabilities();
645 // Did the user pass in a collation, check if our write server supports it
646 if(collation && capabilities && !capabilities.commandsTakeCollation) {
647 return callback(new MongoError(f('server/primary/mongos does not support collation')));
651 bulk.execute(writeCon, function(err, r) {
652 // We have connection level error
653 if(!r && err) return callback(err, null);
654 // We have single error
655 if(r && r.hasWriteErrors() && r.getWriteErrorCount() == 1) {
656 return callback(toError(r.getWriteErrorAt(0)), r);
659 r.insertedCount = r.nInserted;
660 r.matchedCount = r.nMatched;
661 r.modifiedCount = r.nModified || 0;
662 r.deletedCount = r.nRemoved;
663 r.upsertedCount = r.getUpsertedIds().length;
668 r.n = r.insertedCount;
670 // Inserted documents
671 var inserted = r.getInsertedIds();
673 for(var i = 0; i < inserted.length; i++) {
674 r.insertedIds[inserted[i].index] = inserted[i]._id;
677 // Upserted documents
678 var upserted = r.getUpsertedIds();
680 for(var i = 0; i < upserted.length; i++) {
681 r.upsertedIds[upserted[i].index] = upserted[i]._id;
684 // Check if we have write errors
685 if(r.hasWriteErrors()) {
686 // Get all the errors
687 var errors = r.getWriteErrors();
688 // Return the MongoError object
689 return callback(toError({
690 message: 'write operation failed', code: errors[0].code, writeErrors: errors
694 // Check if we have a writeConcern error
695 if(r.getWriteConcernError()) {
696 // Return the MongoError object
697 return callback(toError(r.getWriteConcernError()), r);
700 // Return the results
705 var insertDocuments = function(self, docs, options, callback) {
706 if(typeof options == 'function') callback = options, options = {};
707 options = options || {};
708 // Ensure we are operating on an array op docs
709 docs = Array.isArray(docs) ? docs : [docs];
711 // Get the write concern options
712 var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
713 if(typeof finalOptions.checkKeys != 'boolean') finalOptions.checkKeys = true;
715 // If keep going set unordered
716 if(finalOptions.keepGoing == true) finalOptions.ordered = false;
717 finalOptions['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
719 // Set up the force server object id
720 var forceServerObjectId = typeof options.forceServerObjectId == 'boolean'
721 ? options.forceServerObjectId : self.s.db.options.forceServerObjectId;
723 // Add _id if not specified
724 if(forceServerObjectId !== true){
725 for(var i = 0; i < docs.length; i++) {
726 if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
731 self.s.topology.insert(self.s.namespace, docs, finalOptions, function(err, result) {
732 if(callback == null) return;
733 if(err) return handleCallback(callback, err);
734 if(result == null) return handleCallback(callback, null, null);
735 if(result.result.code) return handleCallback(callback, toError(result.result));
736 if(result.result.writeErrors) return handleCallback(callback, toError(result.result.writeErrors[0]));
737 // Add docs to the list
739 // Return the results
740 handleCallback(callback, null, result);
744 define.classMethod('bulkWrite', {callback: true, promise:true});
747 * @typedef {Object} Collection~WriteOpResult
748 * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
749 * @property {object} connection The connection object used for the operation.
750 * @property {object} result The command result object.
754 * The callback format for inserts
755 * @callback Collection~writeOpCallback
756 * @param {MongoError} error An error instance representing the error during the execution.
757 * @param {Collection~WriteOpResult} result The result object if the command was executed successfully.
761 * @typedef {Object} Collection~insertWriteOpResult
762 * @property {Number} insertedCount The total amount of documents inserted.
763 * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
764 * @property {ObjectId[]} insertedIds All the generated _id's for the inserted documents.
765 * @property {object} connection The connection object used for the operation.
766 * @property {object} result The raw command result object returned from MongoDB (content might vary by server version).
767 * @property {Number} result.ok Is 1 if the command executed correctly.
768 * @property {Number} result.n The total count of documents inserted.
772 * @typedef {Object} Collection~insertOneWriteOpResult
773 * @property {Number} insertedCount The total amount of documents inserted.
774 * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
775 * @property {ObjectId} insertedId The driver generated ObjectId for the insert operation.
776 * @property {object} connection The connection object used for the operation.
777 * @property {object} result The raw command result object returned from MongoDB (content might vary by server version).
778 * @property {Number} result.ok Is 1 if the command executed correctly.
779 * @property {Number} result.n The total count of documents inserted.
783 * The callback format for inserts
784 * @callback Collection~insertWriteOpCallback
785 * @param {MongoError} error An error instance representing the error during the execution.
786 * @param {Collection~insertWriteOpResult} result The result object if the command was executed successfully.
790 * The callback format for inserts
791 * @callback Collection~insertOneWriteOpCallback
792 * @param {MongoError} error An error instance representing the error during the execution.
793 * @param {Collection~insertOneWriteOpResult} result The result object if the command was executed successfully.
797 * Inserts a single document or a an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
798 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
799 * can be overridden by setting the **forceServerObjectId** flag.
802 * @param {(object|object[])} docs Documents to insert.
803 * @param {object} [options=null] Optional settings.
804 * @param {(number|string)} [options.w=null] The write concern.
805 * @param {number} [options.wtimeout=null] The write concern timeout.
806 * @param {boolean} [options.j=false] Specify a journal write concern.
807 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
808 * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
809 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
810 * @param {Collection~insertWriteOpCallback} [callback] The command result callback
811 * @return {Promise} returns Promise if no callback passed
812 * @deprecated Use insertOne, insertMany or bulkWrite
814 Collection.prototype.insert = function(docs, options, callback) {
816 if(typeof options == 'function') callback = options, options = {};
817 options = options || {ordered:false};
818 docs = !Array.isArray(docs) ? [docs] : docs;
820 if(options.keepGoing == true) {
821 options.ordered = false;
824 return this.insertMany(docs, options, callback);
827 define.classMethod('insert', {callback: true, promise:true});
830 * @typedef {Object} Collection~updateWriteOpResult
831 * @property {Object} result The raw result returned from MongoDB, field will vary depending on server version.
832 * @property {Number} result.ok Is 1 if the command executed correctly.
833 * @property {Number} result.n The total count of documents scanned.
834 * @property {Number} result.nModified The total count of documents modified.
835 * @property {Object} connection The connection object used for the operation.
836 * @property {Number} matchedCount The number of documents that matched the filter.
837 * @property {Number} modifiedCount The number of documents that were modified.
838 * @property {Number} upsertedCount The number of documents upserted.
839 * @property {Object} upsertedId The upserted id.
840 * @property {ObjectId} upsertedId._id The upserted _id returned from the server.
844 * The callback format for inserts
845 * @callback Collection~updateWriteOpCallback
846 * @param {MongoError} error An error instance representing the error during the execution.
847 * @param {Collection~updateWriteOpResult} result The result object if the command was executed successfully.
851 * Update a single document on MongoDB
853 * @param {object} filter The Filter used to select the document to update
854 * @param {object} update The update operations to be applied to the document
855 * @param {object} [options=null] Optional settings.
856 * @param {boolean} [options.upsert=false] Update operation is an upsert.
857 * @param {(number|string)} [options.w=null] The write concern.
858 * @param {number} [options.wtimeout=null] The write concern timeout.
859 * @param {boolean} [options.j=false] Specify a journal write concern.
860 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
861 * @param {Collection~updateWriteOpCallback} [callback] The command result callback
862 * @return {Promise} returns Promise if no callback passed
864 Collection.prototype.updateOne = function(filter, update, options, callback) {
866 if(typeof options == 'function') callback = options, options = {};
867 options = shallowClone(options)
869 // Add ignoreUndfined
870 if(this.s.options.ignoreUndefined) {
871 options = shallowClone(options);
872 options.ignoreUndefined = this.s.options.ignoreUndefined;
875 // Execute using callback
876 if(typeof callback == 'function') return updateOne(self, filter, update, options, callback);
879 return new this.s.promiseLibrary(function(resolve, reject) {
880 updateOne(self, filter, update, options, function(err, r) {
881 if(err) return reject(err);
887 var updateOne = function(self, filter, update, options, callback) {
888 // Set single document update
889 options.multi = false;
891 updateDocuments(self, filter, update, options, function(err, r) {
892 if(callback == null) return;
893 if(err && callback) return callback(err);
894 if(r == null) return callback(null, {result: {ok:1}});
895 r.matchedCount = r.result.n;
896 r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
897 r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
898 r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
899 if(callback) callback(null, r);
903 define.classMethod('updateOne', {callback: true, promise:true});
906 * Replace a document on MongoDB
908 * @param {object} filter The Filter used to select the document to update
909 * @param {object} doc The Document that replaces the matching document
910 * @param {object} [options=null] Optional settings.
911 * @param {boolean} [options.upsert=false] Update operation is an upsert.
912 * @param {(number|string)} [options.w=null] The write concern.
913 * @param {number} [options.wtimeout=null] The write concern timeout.
914 * @param {boolean} [options.j=false] Specify a journal write concern.
915 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
916 * @param {Collection~updateWriteOpCallback} [callback] The command result callback
917 * @return {Promise} returns Promise if no callback passed
919 Collection.prototype.replaceOne = function(filter, update, options, callback) {
921 if(typeof options == 'function') callback = options, options = {};
922 options = shallowClone(options)
924 // Add ignoreUndfined
925 if(this.s.options.ignoreUndefined) {
926 options = shallowClone(options);
927 options.ignoreUndefined = this.s.options.ignoreUndefined;
930 // Execute using callback
931 if(typeof callback == 'function') return replaceOne(self, filter, update, options, callback);
934 return new this.s.promiseLibrary(function(resolve, reject) {
935 replaceOne(self, filter, update, options, function(err, r) {
936 if(err) return reject(err);
942 var replaceOne = function(self, filter, update, options, callback) {
943 // Set single document update
944 options.multi = false;
946 updateDocuments(self, filter, update, options, function(err, r) {
947 if(callback == null) return;
948 if(err && callback) return callback(err);
949 if(r == null) return callback(null, {result: {ok:1}});
950 r.matchedCount = r.result.n;
951 r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
952 r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
953 r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
955 if(callback) callback(null, r);
959 define.classMethod('replaceOne', {callback: true, promise:true});
962 * Update multiple documents on MongoDB
964 * @param {object} filter The Filter used to select the document to update
965 * @param {object} update The update operations to be applied to the document
966 * @param {object} [options=null] Optional settings.
967 * @param {boolean} [options.upsert=false] Update operation is an upsert.
968 * @param {(number|string)} [options.w=null] The write concern.
969 * @param {number} [options.wtimeout=null] The write concern timeout.
970 * @param {boolean} [options.j=false] Specify a journal write concern.
971 * @param {Collection~updateWriteOpCallback} [callback] The command result callback
972 * @return {Promise} returns Promise if no callback passed
974 Collection.prototype.updateMany = function(filter, update, options, callback) {
976 if(typeof options == 'function') callback = options, options = {};
977 options = shallowClone(options)
979 // Add ignoreUndfined
980 if(this.s.options.ignoreUndefined) {
981 options = shallowClone(options);
982 options.ignoreUndefined = this.s.options.ignoreUndefined;
985 // Execute using callback
986 if(typeof callback == 'function') return updateMany(self, filter, update, options, callback);
989 return new this.s.promiseLibrary(function(resolve, reject) {
990 updateMany(self, filter, update, options, function(err, r) {
991 if(err) return reject(err);
997 var updateMany = function(self, filter, update, options, callback) {
998 // Set single document update
999 options.multi = true;
1001 updateDocuments(self, filter, update, options, function(err, r) {
1002 if(callback == null) return;
1003 if(err && callback) return callback(err);
1004 if(r == null) return callback(null, {result: {ok:1}});
1005 r.matchedCount = r.result.n;
1006 r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
1007 r.upsertedId = Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? r.result.upserted[0] : null;
1008 r.upsertedCount = Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
1009 if(callback) callback(null, r);
1013 define.classMethod('updateMany', {callback: true, promise:true});
1015 var updateDocuments = function(self, selector, document, options, callback) {
1016 if('function' === typeof options) callback = options, options = null;
1017 if(options == null) options = {};
1018 if(!('function' === typeof callback)) callback = null;
1020 // If we are not providing a selector or document throw
1021 if(selector == null || typeof selector != 'object') return callback(toError("selector must be a valid JavaScript object"));
1022 if(document == null || typeof document != 'object') return callback(toError("document must be a valid JavaScript object"));
1024 // Get the write concern options
1025 var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
1027 // Do we return the actual result document
1028 // Either use override on the function, or go back to default on either the collection
1030 finalOptions['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
1032 // Execute the operation
1033 var op = {q: selector, u: document};
1034 op.upsert = typeof options.upsert == 'boolean' ? options.upsert : false;
1035 op.multi = typeof options.multi == 'boolean' ? options.multi : false;
1037 // Have we specified collation
1038 decorateWithCollation(finalOptions, self, options);
1041 self.s.topology.update(self.s.namespace, [op], finalOptions, function(err, result) {
1042 if(callback == null) return;
1043 if(err) return handleCallback(callback, err, null);
1044 if(result == null) return handleCallback(callback, null, null);
1045 if(result.result.code) return handleCallback(callback, toError(result.result));
1046 if(result.result.writeErrors) return handleCallback(callback, toError(result.result.writeErrors[0]));
1047 // Return the results
1048 handleCallback(callback, null, result);
1053 * Updates documents.
1055 * @param {object} selector The selector for the update operation.
1056 * @param {object} document The update document.
1057 * @param {object} [options=null] Optional settings.
1058 * @param {(number|string)} [options.w=null] The write concern.
1059 * @param {number} [options.wtimeout=null] The write concern timeout.
1060 * @param {boolean} [options.j=false] Specify a journal write concern.
1061 * @param {boolean} [options.upsert=false] Update operation is an upsert.
1062 * @param {boolean} [options.multi=false] Update one/all documents with operation.
1063 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
1064 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
1065 * @param {Collection~writeOpCallback} [callback] The command result callback
1066 * @throws {MongoError}
1067 * @return {Promise} returns Promise if no callback passed
1068 * @deprecated use updateOne, updateMany or bulkWrite
1070 Collection.prototype.update = function(selector, document, options, callback) {
1073 // Add ignoreUndfined
1074 if(this.s.options.ignoreUndefined) {
1075 options = shallowClone(options);
1076 options.ignoreUndefined = this.s.options.ignoreUndefined;
1079 // Execute using callback
1080 if(typeof callback == 'function') return updateDocuments(self, selector, document, options, callback);
1083 return new this.s.promiseLibrary(function(resolve, reject) {
1084 updateDocuments(self, selector, document, options, function(err, r) {
1085 if(err) return reject(err);
1091 define.classMethod('update', {callback: true, promise:true});
1094 * @typedef {Object} Collection~deleteWriteOpResult
1095 * @property {Object} result The raw result returned from MongoDB, field will vary depending on server version.
1096 * @property {Number} result.ok Is 1 if the command executed correctly.
1097 * @property {Number} result.n The total count of documents deleted.
1098 * @property {Object} connection The connection object used for the operation.
1099 * @property {Number} deletedCount The number of documents deleted.
1103 * The callback format for inserts
1104 * @callback Collection~deleteWriteOpCallback
1105 * @param {MongoError} error An error instance representing the error during the execution.
1106 * @param {Collection~deleteWriteOpResult} result The result object if the command was executed successfully.
1110 * Delete a document on MongoDB
1112 * @param {object} filter The Filter used to select the document to remove
1113 * @param {object} [options=null] Optional settings.
1114 * @param {(number|string)} [options.w=null] The write concern.
1115 * @param {number} [options.wtimeout=null] The write concern timeout.
1116 * @param {boolean} [options.j=false] Specify a journal write concern.
1117 * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
1118 * @return {Promise} returns Promise if no callback passed
1120 Collection.prototype.deleteOne = function(filter, options, callback) {
1122 if(typeof options == 'function') callback = options, options = {};
1123 var options = shallowClone(options);
1125 // Add ignoreUndfined
1126 if(this.s.options.ignoreUndefined) {
1127 options = shallowClone(options);
1128 options.ignoreUndefined = this.s.options.ignoreUndefined;
1131 // Execute using callback
1132 if(typeof callback == 'function') return deleteOne(self, filter, options, callback);
1135 return new this.s.promiseLibrary(function(resolve, reject) {
1136 deleteOne(self, filter, options, function(err, r) {
1137 if(err) return reject(err);
1143 var deleteOne = function(self, filter, options, callback) {
1144 options.single = true;
1145 removeDocuments(self, filter, options, function(err, r) {
1146 if(callback == null) return;
1147 if(err && callback) return callback(err);
1148 if(r == null) return callback(null, {result: {ok:1}});
1149 r.deletedCount = r.result.n;
1150 if(callback) callback(null, r);
1154 define.classMethod('deleteOne', {callback: true, promise:true});
1156 Collection.prototype.removeOne = Collection.prototype.deleteOne;
1158 define.classMethod('removeOne', {callback: true, promise:true});
1161 * Delete multiple documents on MongoDB
1163 * @param {object} filter The Filter used to select the documents to remove
1164 * @param {object} [options=null] Optional settings.
1165 * @param {(number|string)} [options.w=null] The write concern.
1166 * @param {number} [options.wtimeout=null] The write concern timeout.
1167 * @param {boolean} [options.j=false] Specify a journal write concern.
1168 * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
1169 * @return {Promise} returns Promise if no callback passed
1171 Collection.prototype.deleteMany = function(filter, options, callback) {
1173 if(typeof options == 'function') callback = options, options = {};
1174 var options = shallowClone(options);
1176 // Add ignoreUndfined
1177 if(this.s.options.ignoreUndefined) {
1178 options = shallowClone(options);
1179 options.ignoreUndefined = this.s.options.ignoreUndefined;
1182 // Execute using callback
1183 if(typeof callback == 'function') return deleteMany(self, filter, options, callback);
1186 return new this.s.promiseLibrary(function(resolve, reject) {
1187 deleteMany(self, filter, options, function(err, r) {
1188 if(err) return reject(err);
1194 var deleteMany = function(self, filter, options, callback) {
1195 options.single = false;
1197 removeDocuments(self, filter, options, function(err, r) {
1198 if(callback == null) return;
1199 if(err && callback) return callback(err);
1200 if(r == null) return callback(null, {result: {ok:1}});
1201 r.deletedCount = r.result.n;
1202 if(callback) callback(null, r);
1206 var removeDocuments = function(self, selector, options, callback) {
1207 if(typeof options == 'function') {
1208 callback = options, options = {};
1209 } else if (typeof selector === 'function') {
1210 callback = selector;
1215 // Create an empty options object if the provided one is null
1216 options = options || {};
1218 // Get the write concern options
1219 var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
1221 // If selector is null set empty
1222 if(selector == null) selector = {};
1225 var op = {q: selector, limit: 0};
1226 if(options.single) op.limit = 1;
1228 // Have we specified collation
1229 decorateWithCollation(finalOptions, self, options);
1231 // Execute the remove
1232 self.s.topology.remove(self.s.namespace, [op], finalOptions, function(err, result) {
1233 if(callback == null) return;
1234 if(err) return handleCallback(callback, err, null);
1235 if(result == null) return handleCallback(callback, null, null);
1236 if(result.result.code) return handleCallback(callback, toError(result.result));
1237 if(result.result.writeErrors) return handleCallback(callback, toError(result.result.writeErrors[0]));
1238 // Return the results
1239 handleCallback(callback, null, result);
1243 define.classMethod('deleteMany', {callback: true, promise:true});
1245 Collection.prototype.removeMany = Collection.prototype.deleteMany;
1247 define.classMethod('removeMany', {callback: true, promise:true});
1252 * @param {object} selector The selector for the update operation.
1253 * @param {object} [options=null] Optional settings.
1254 * @param {(number|string)} [options.w=null] The write concern.
1255 * @param {number} [options.wtimeout=null] The write concern timeout.
1256 * @param {boolean} [options.j=false] Specify a journal write concern.
1257 * @param {boolean} [options.single=false] Removes the first document found.
1258 * @param {Collection~writeOpCallback} [callback] The command result callback
1259 * @return {Promise} returns Promise if no callback passed
1260 * @deprecated use deleteOne, deleteMany or bulkWrite
1262 Collection.prototype.remove = function(selector, options, callback) {
1265 // Add ignoreUndfined
1266 if(this.s.options.ignoreUndefined) {
1267 options = shallowClone(options);
1268 options.ignoreUndefined = this.s.options.ignoreUndefined;
1271 // Execute using callback
1272 if(typeof callback == 'function') return removeDocuments(self, selector, options, callback);
1275 return new this.s.promiseLibrary(function(resolve, reject) {
1276 removeDocuments(self, selector, options, function(err, r) {
1277 if(err) return reject(err);
1283 define.classMethod('remove', {callback: true, promise:true});
1286 * Save a document. Simple full document replacement function. Not recommended for efficiency, use atomic
1287 * operators and update instead for more efficient operations.
1289 * @param {object} doc Document to save
1290 * @param {object} [options=null] Optional settings.
1291 * @param {(number|string)} [options.w=null] The write concern.
1292 * @param {number} [options.wtimeout=null] The write concern timeout.
1293 * @param {boolean} [options.j=false] Specify a journal write concern.
1294 * @param {Collection~writeOpCallback} [callback] The command result callback
1295 * @return {Promise} returns Promise if no callback passed
1296 * @deprecated use insertOne, insertMany, updateOne or updateMany
1298 Collection.prototype.save = function(doc, options, callback) {
1300 if(typeof options == 'function') callback = options, options = {};
1301 options = options || {};
1303 // Add ignoreUndfined
1304 if(this.s.options.ignoreUndefined) {
1305 options = shallowClone(options);
1306 options.ignoreUndefined = this.s.options.ignoreUndefined;
1309 // Execute using callback
1310 if(typeof callback == 'function') return save(self, doc, options, callback);
1313 return new this.s.promiseLibrary(function(resolve, reject) {
1314 save(self, doc, options, function(err, r) {
1315 if(err) return reject(err);
1321 var save = function(self, doc, options, callback) {
1322 // Get the write concern options
1323 var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
1324 // Establish if we need to perform an insert or update
1325 if(doc._id != null) {
1326 finalOptions.upsert = true;
1327 return updateDocuments(self, {_id: doc._id}, doc, finalOptions, callback);
1330 // Insert the document
1331 insertDocuments(self, [doc], options, function(err, r) {
1332 if(callback == null) return;
1333 if(doc == null) return handleCallback(callback, null, null);
1334 if(err) return handleCallback(callback, err, null);
1335 handleCallback(callback, null, r);
1339 define.classMethod('save', {callback: true, promise:true});
1342 * The callback format for results
1343 * @callback Collection~resultCallback
1344 * @param {MongoError} error An error instance representing the error during the execution.
1345 * @param {object} result The result object if the command was executed successfully.
1349 * Fetches the first document that matches the query
1351 * @param {object} query Query for find Operation
1352 * @param {object} [options=null] Optional settings.
1353 * @param {number} [options.limit=0] Sets the limit of documents returned in the query.
1354 * @param {(array|object)} [options.sort=null] Set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
1355 * @param {object} [options.fields=null] The fields to return in the query. Object of fields to include or exclude (not both), {'a':1}
1356 * @param {number} [options.skip=0] Set to skip N documents ahead in your query (useful for pagination).
1357 * @param {Object} [options.hint=null] Tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
1358 * @param {boolean} [options.explain=false] Explain the query instead of returning the data.
1359 * @param {boolean} [options.snapshot=false] Snapshot query.
1360 * @param {boolean} [options.timeout=false] Specify if the cursor can timeout.
1361 * @param {boolean} [options.tailable=false] Specify if the cursor is tailable.
1362 * @param {number} [options.batchSize=0] Set the batchSize for the getMoreCommand when iterating over the query results.
1363 * @param {boolean} [options.returnKey=false] Only return the index key.
1364 * @param {number} [options.maxScan=null] Limit the number of items to scan.
1365 * @param {number} [options.min=null] Set index bounds.
1366 * @param {number} [options.max=null] Set index bounds.
1367 * @param {boolean} [options.showDiskLoc=false] Show disk location of results.
1368 * @param {string} [options.comment=null] You can put a $comment field on a query to make looking in the profiler logs simpler.
1369 * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
1370 * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
1371 * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
1372 * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
1373 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1374 * @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
1375 * @param {number} [options.maxTimeMS=null] Number of miliseconds to wait before aborting the query.
1376 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
1377 * @param {Collection~resultCallback} [callback] The command result callback
1378 * @return {Promise} returns Promise if no callback passed
1380 Collection.prototype.findOne = function() {
1382 var args = Array.prototype.slice.call(arguments, 0);
1383 var callback = args.pop();
1384 if(typeof callback != 'function') args.push(callback);
1386 // Execute using callback
1387 if(typeof callback == 'function') return findOne(self, args, callback);
1390 return new this.s.promiseLibrary(function(resolve, reject) {
1391 findOne(self, args, function(err, r) {
1392 if(err) return reject(err);
1398 var findOne = function(self, args, callback) {
1399 var cursor = self.find.apply(self, args).limit(-1).batchSize(1);
1401 cursor.next(function(err, item) {
1402 if(err != null) return handleCallback(callback, toError(err), null);
1403 handleCallback(callback, null, item);
1407 define.classMethod('findOne', {callback: true, promise:true});
1410 * The callback format for the collection method, must be used if strict is specified
1411 * @callback Collection~collectionResultCallback
1412 * @param {MongoError} error An error instance representing the error during the execution.
1413 * @param {Collection} collection The collection instance.
1417 * Rename the collection.
1420 * @param {string} newName New name of of the collection.
1421 * @param {object} [options=null] Optional settings.
1422 * @param {boolean} [options.dropTarget=false] Drop the target name collection if it previously exists.
1423 * @param {Collection~collectionResultCallback} [callback] The results callback
1424 * @return {Promise} returns Promise if no callback passed
1426 Collection.prototype.rename = function(newName, opt, callback) {
1428 if(typeof opt == 'function') callback = opt, opt = {};
1429 opt = assign({}, opt, {readPreference: ReadPreference.PRIMARY});
1431 // Execute using callback
1432 if(typeof callback == 'function') return rename(self, newName, opt, callback);
1435 return new this.s.promiseLibrary(function(resolve, reject) {
1436 rename(self, newName, opt, function(err, r) {
1437 if(err) return reject(err);
1443 var rename = function(self, newName, opt, callback) {
1444 // Check the collection name
1445 checkCollectionName(newName);
1446 // Build the command
1447 var renameCollection = f("%s.%s", self.s.dbName, self.s.name);
1448 var toCollection = f("%s.%s", self.s.dbName, newName);
1449 var dropTarget = typeof opt.dropTarget == 'boolean' ? opt.dropTarget : false;
1450 var cmd = {'renameCollection':renameCollection, 'to':toCollection, 'dropTarget':dropTarget};
1452 // Decorate command with writeConcern if supported
1453 decorateWithWriteConcern(cmd, self, opt);
1455 // Execute against admin
1456 self.s.db.admin().command(cmd, opt, function(err, doc) {
1457 if(err) return handleCallback(callback, err, null);
1459 if(doc.errmsg) return handleCallback(callback, toError(doc), null);
1461 return handleCallback(callback, null, new Collection(self.s.db, self.s.topology, self.s.dbName, newName, self.s.pkFactory, self.s.options));
1463 return handleCallback(callback, toError(err), null);
1468 define.classMethod('rename', {callback: true, promise:true});
1471 * Drop the collection from the database, removing it permanently. New accesses will create a new collection.
1474 * @param {object} [options=null] Optional settings.
1475 * @param {Collection~resultCallback} [callback] The results callback
1476 * @return {Promise} returns Promise if no callback passed
1478 Collection.prototype.drop = function(options, callback) {
1480 if(typeof options == 'function') callback = options, options = {};
1481 options = options || {};
1483 // Execute using callback
1484 if(typeof callback == 'function') return self.s.db.dropCollection(self.s.name, options, callback);
1486 return new this.s.promiseLibrary(function(resolve, reject) {
1487 self.s.db.dropCollection(self.s.name, options, function(err, r) {
1488 if(err) return reject(err);
1494 define.classMethod('drop', {callback: true, promise:true});
1497 * Returns the options of the collection.
1500 * @param {Collection~resultCallback} [callback] The results callback
1501 * @return {Promise} returns Promise if no callback passed
1503 Collection.prototype.options = function(callback) {
1506 // Execute using callback
1507 if(typeof callback == 'function') return options(self, callback);
1510 return new this.s.promiseLibrary(function(resolve, reject) {
1511 options(self, function(err, r) {
1512 if(err) return reject(err);
1518 var options = function(self, callback) {
1519 self.s.db.listCollections({name: self.s.name}).toArray(function(err, collections) {
1520 if(err) return handleCallback(callback, err);
1521 if(collections.length == 0) {
1522 return handleCallback(callback, MongoError.create({message: f("collection %s not found", self.s.namespace), driver:true }));
1525 handleCallback(callback, err, collections[0].options || null);
1529 define.classMethod('options', {callback: true, promise:true});
1532 * Returns if the collection is a capped collection
1535 * @param {Collection~resultCallback} [callback] The results callback
1536 * @return {Promise} returns Promise if no callback passed
1538 Collection.prototype.isCapped = function(callback) {
1541 // Execute using callback
1542 if(typeof callback == 'function') return isCapped(self, callback);
1545 return new this.s.promiseLibrary(function(resolve, reject) {
1546 isCapped(self, function(err, r) {
1547 if(err) return reject(err);
1553 var isCapped = function(self, callback) {
1554 self.options(function(err, document) {
1555 if(err) return handleCallback(callback, err);
1556 handleCallback(callback, null, document && document.capped);
1560 define.classMethod('isCapped', {callback: true, promise:true});
1563 * Creates an index on the db and collection collection.
1565 * @param {(string|object)} fieldOrSpec Defines the index.
1566 * @param {object} [options=null] Optional settings.
1567 * @param {(number|string)} [options.w=null] The write concern.
1568 * @param {number} [options.wtimeout=null] The write concern timeout.
1569 * @param {boolean} [options.j=false] Specify a journal write concern.
1570 * @param {boolean} [options.unique=false] Creates an unique index.
1571 * @param {boolean} [options.sparse=false] Creates a sparse index.
1572 * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
1573 * @param {boolean} [options.dropDups=false] A unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
1574 * @param {number} [options.min=null] For geospatial indexes set the lower bound for the co-ordinates.
1575 * @param {number} [options.max=null] For geospatial indexes set the high bound for the co-ordinates.
1576 * @param {number} [options.v=null] Specify the format version of the indexes.
1577 * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
1578 * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
1579 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
1580 * @param {Collection~resultCallback} [callback] The command result callback
1581 * @return {Promise} returns Promise if no callback passed
1583 Collection.prototype.createIndex = function(fieldOrSpec, options, callback) {
1585 var args = Array.prototype.slice.call(arguments, 1);
1586 callback = args.pop();
1587 if(typeof callback != 'function') args.push(callback);
1588 options = args.length ? args.shift() || {} : {};
1589 options = typeof callback === 'function' ? options : callback;
1590 options = options == null ? {} : options;
1592 // Execute using callback
1593 if(typeof callback == 'function') return createIndex(self, fieldOrSpec, options, callback);
1596 return new this.s.promiseLibrary(function(resolve, reject) {
1597 createIndex(self, fieldOrSpec, options, function(err, r) {
1598 if(err) return reject(err);
1604 var createIndex = function(self, fieldOrSpec, options, callback) {
1605 self.s.db.createIndex(self.s.name, fieldOrSpec, options, callback);
1608 define.classMethod('createIndex', {callback: true, promise:true});
1611 * Creates multiple indexes in the collection, this method is only supported for
1612 * MongoDB 2.6 or higher. Earlier version of MongoDB will throw a command not supported
1613 * error. Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/.
1615 * @param {array} indexSpecs An array of index specifications to be created
1616 * @param {Collection~resultCallback} [callback] The command result callback
1617 * @return {Promise} returns Promise if no callback passed
1619 Collection.prototype.createIndexes = function(indexSpecs, callback) {
1622 // Execute using callback
1623 if(typeof callback == 'function') return createIndexes(self, indexSpecs, callback);
1626 return new this.s.promiseLibrary(function(resolve, reject) {
1627 createIndexes(self, indexSpecs, function(err, r) {
1628 if(err) return reject(err);
1634 var createIndexes = function(self, indexSpecs, callback) {
1635 var capabilities = self.s.topology.capabilities();
1637 // Ensure we generate the correct name if the parameter is not set
1638 for(var i = 0; i < indexSpecs.length; i++) {
1639 if(indexSpecs[i].name == null) {
1642 // Did the user pass in a collation, check if our write server supports it
1643 if(indexSpecs[i].collation && capabilities && !capabilities.commandsTakeCollation) {
1644 return callback(new MongoError(f('server/primary/mongos does not support collation')));
1647 for(var name in indexSpecs[i].key) {
1648 keys.push(f('%s_%s', name, indexSpecs[i].key[name]));
1652 indexSpecs[i].name = keys.join('_');
1656 // Execute the index
1658 createIndexes: self.s.name, indexes: indexSpecs
1659 }, { readPreference: ReadPreference.PRIMARY }, callback);
1662 define.classMethod('createIndexes', {callback: true, promise:true});
1665 * Drops an index from this collection.
1667 * @param {string} indexName Name of the index to drop.
1668 * @param {object} [options=null] Optional settings.
1669 * @param {(number|string)} [options.w=null] The write concern.
1670 * @param {number} [options.wtimeout=null] The write concern timeout.
1671 * @param {boolean} [options.j=false] Specify a journal write concern.
1672 * @param {Collection~resultCallback} [callback] The command result callback
1673 * @return {Promise} returns Promise if no callback passed
1675 Collection.prototype.dropIndex = function(indexName, options, callback) {
1677 var args = Array.prototype.slice.call(arguments, 1);
1678 callback = args.pop();
1679 if(typeof callback != 'function') args.push(callback);
1680 options = args.length ? args.shift() || {} : {};
1681 // Run only against primary
1682 options.readPreference = ReadPreference.PRIMARY;
1684 // Execute using callback
1685 if(typeof callback == 'function') return dropIndex(self, indexName, options, callback);
1688 return new this.s.promiseLibrary(function(resolve, reject) {
1689 dropIndex(self, indexName, options, function(err, r) {
1690 if(err) return reject(err);
1696 var dropIndex = function(self, indexName, options, callback) {
1697 // Delete index command
1698 var cmd = {'dropIndexes':self.s.name, 'index':indexName};
1700 // Decorate command with writeConcern if supported
1701 decorateWithWriteConcern(cmd, self, options);
1704 self.s.db.command(cmd, options, function(err, result) {
1705 if(typeof callback != 'function') return;
1706 if(err) return handleCallback(callback, err, null);
1707 handleCallback(callback, null, result);
1711 define.classMethod('dropIndex', {callback: true, promise:true});
1714 * Drops all indexes from this collection.
1716 * @param {Collection~resultCallback} [callback] The command result callback
1717 * @return {Promise} returns Promise if no callback passed
1719 Collection.prototype.dropIndexes = function(options, callback) {
1722 // Do we have options
1723 if(typeof options == 'function') callback = options, options = {};
1724 options = options || {};
1726 // Execute using callback
1727 if(typeof callback == 'function') return dropIndexes(self, options, callback);
1730 return new this.s.promiseLibrary(function(resolve, reject) {
1731 dropIndexes(self, function(err, r) {
1732 if(err) return reject(err);
1738 var dropIndexes = function(self, options, callback) {
1739 self.dropIndex('*', options, function(err, result) {
1740 if(err) return handleCallback(callback, err, false);
1741 handleCallback(callback, null, true);
1745 define.classMethod('dropIndexes', {callback: true, promise:true});
1748 * Drops all indexes from this collection.
1750 * @deprecated use dropIndexes
1751 * @param {Collection~resultCallback} callback The command result callback
1752 * @return {Promise} returns Promise if no [callback] passed
1754 Collection.prototype.dropAllIndexes = Collection.prototype.dropIndexes;
1756 define.classMethod('dropAllIndexes', {callback: true, promise:true});
1759 * Reindex all indexes on the collection
1760 * Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
1762 * @param {Collection~resultCallback} [callback] The command result callback
1763 * @return {Promise} returns Promise if no callback passed
1765 Collection.prototype.reIndex = function(options, callback) {
1767 if(typeof options == 'function') callback = options, options = {};
1768 options = options || {};
1770 // Execute using callback
1771 if(typeof callback == 'function') return reIndex(self, options, callback);
1774 return new this.s.promiseLibrary(function(resolve, reject) {
1775 reIndex(self, options, function(err, r) {
1776 if(err) return reject(err);
1782 var reIndex = function(self, options, callback) {
1784 var cmd = {'reIndex':self.s.name};
1786 // Decorate command with writeConcern if supported
1787 decorateWithWriteConcern(cmd, self, options);
1789 // Execute the command
1790 self.s.db.command(cmd, options, function(err, result) {
1791 if(callback == null) return;
1792 if(err) return handleCallback(callback, err, null);
1793 handleCallback(callback, null, result.ok ? true : false);
1797 define.classMethod('reIndex', {callback: true, promise:true});
1800 * Get the list of all indexes information for the collection.
1803 * @param {object} [options=null] Optional settings.
1804 * @param {number} [options.batchSize=null] The batchSize for the returned command cursor or if pre 2.8 the systems batch collection
1805 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1806 * @return {CommandCursor}
1808 Collection.prototype.listIndexes = function(options) {
1809 options = options || {};
1810 // Clone the options
1811 options = shallowClone(options);
1812 // Determine the read preference in the options.
1813 options = getReadPreference(this, options, this.s.db, this);
1814 // Set the CommandCursor constructor
1815 options.cursorFactory = CommandCursor;
1816 // Set the promiseLibrary
1817 options.promiseLibrary = this.s.promiseLibrary;
1819 if(!this.s.topology.capabilities()) {
1820 throw new MongoError('cannot connect to server');
1823 // We have a list collections command
1824 if(this.s.topology.capabilities().hasListIndexesCommand) {
1826 var cursor = options.batchSize ? {batchSize: options.batchSize} : {}
1827 // Build the command
1828 var command = { listIndexes: this.s.name, cursor: cursor };
1829 // Execute the cursor
1830 var cursor = this.s.topology.cursor(f('%s.$cmd', this.s.dbName), command, options);
1831 // Do we have a readPreference, apply it
1832 if(options.readPreference) cursor.setReadPreference(options.readPreference);
1833 // Return the cursor
1837 // Get the namespace
1838 var ns = f('%s.system.indexes', this.s.dbName);
1840 var cursor = this.s.topology.cursor(ns, {find: ns, query: {ns: this.s.namespace}}, options);
1841 // Do we have a readPreference, apply it
1842 if(options.readPreference) cursor.setReadPreference(options.readPreference);
1843 // Set the passed in batch size if one was provided
1844 if(options.batchSize) cursor = cursor.batchSize(options.batchSize);
1845 // Return the cursor
1849 define.classMethod('listIndexes', {callback: false, promise:false, returns: [CommandCursor]});
1852 * Ensures that an index exists, if it does not it creates it
1854 * @deprecated use createIndexes instead
1855 * @param {(string|object)} fieldOrSpec Defines the index.
1856 * @param {object} [options=null] Optional settings.
1857 * @param {(number|string)} [options.w=null] The write concern.
1858 * @param {number} [options.wtimeout=null] The write concern timeout.
1859 * @param {boolean} [options.j=false] Specify a journal write concern.
1860 * @param {boolean} [options.unique=false] Creates an unique index.
1861 * @param {boolean} [options.sparse=false] Creates a sparse index.
1862 * @param {boolean} [options.background=false] Creates the index in the background, yielding whenever possible.
1863 * @param {boolean} [options.dropDups=false] A unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
1864 * @param {number} [options.min=null] For geospatial indexes set the lower bound for the co-ordinates.
1865 * @param {number} [options.max=null] For geospatial indexes set the high bound for the co-ordinates.
1866 * @param {number} [options.v=null] Specify the format version of the indexes.
1867 * @param {number} [options.expireAfterSeconds=null] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
1868 * @param {number} [options.name=null] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
1869 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
1870 * @param {Collection~resultCallback} [callback] The command result callback
1871 * @return {Promise} returns Promise if no callback passed
1873 Collection.prototype.ensureIndex = function(fieldOrSpec, options, callback) {
1875 if(typeof options == 'function') callback = options, options = {};
1876 options = options || {};
1878 // Execute using callback
1879 if(typeof callback == 'function') return ensureIndex(self, fieldOrSpec, options, callback);
1882 return new this.s.promiseLibrary(function(resolve, reject) {
1883 ensureIndex(self, fieldOrSpec, options, function(err, r) {
1884 if(err) return reject(err);
1890 var ensureIndex = function(self, fieldOrSpec, options, callback) {
1891 self.s.db.ensureIndex(self.s.name, fieldOrSpec, options, callback);
1894 define.classMethod('ensureIndex', {callback: true, promise:true});
1897 * Checks if one or more indexes exist on the collection, fails on first non-existing index
1899 * @param {(string|array)} indexes One or more index names to check.
1900 * @param {Collection~resultCallback} [callback] The command result callback
1901 * @return {Promise} returns Promise if no callback passed
1903 Collection.prototype.indexExists = function(indexes, callback) {
1906 // Execute using callback
1907 if(typeof callback == 'function') return indexExists(self, indexes, callback);
1910 return new this.s.promiseLibrary(function(resolve, reject) {
1911 indexExists(self, indexes, function(err, r) {
1912 if(err) return reject(err);
1918 var indexExists = function(self, indexes, callback) {
1919 self.indexInformation(function(err, indexInformation) {
1920 // If we have an error return
1921 if(err != null) return handleCallback(callback, err, null);
1922 // Let's check for the index names
1923 if(!Array.isArray(indexes)) return handleCallback(callback, null, indexInformation[indexes] != null);
1924 // Check in list of indexes
1925 for(var i = 0; i < indexes.length; i++) {
1926 if(indexInformation[indexes[i]] == null) {
1927 return handleCallback(callback, null, false);
1931 // All keys found return true
1932 return handleCallback(callback, null, true);
1936 define.classMethod('indexExists', {callback: true, promise:true});
1939 * Retrieves this collections index info.
1941 * @param {object} [options=null] Optional settings.
1942 * @param {boolean} [options.full=false] Returns the full raw index information.
1943 * @param {Collection~resultCallback} [callback] The command result callback
1944 * @return {Promise} returns Promise if no callback passed
1946 Collection.prototype.indexInformation = function(options, callback) {
1949 var args = Array.prototype.slice.call(arguments, 0);
1950 callback = args.pop();
1951 if(typeof callback != 'function') args.push(callback);
1952 options = args.length ? args.shift() || {} : {};
1954 // Execute using callback
1955 if(typeof callback == 'function') return indexInformation(self, options, callback);
1958 return new this.s.promiseLibrary(function(resolve, reject) {
1959 indexInformation(self, options, function(err, r) {
1960 if(err) return reject(err);
1966 var indexInformation = function(self, options, callback) {
1967 self.s.db.indexInformation(self.s.name, options, callback);
1970 define.classMethod('indexInformation', {callback: true, promise:true});
1973 * The callback format for results
1974 * @callback Collection~countCallback
1975 * @param {MongoError} error An error instance representing the error during the execution.
1976 * @param {number} result The count of documents that matched the query.
1980 * Count number of matching documents in the db to a query.
1982 * @param {object} query The query for the count.
1983 * @param {object} [options=null] Optional settings.
1984 * @param {boolean} [options.limit=null] The limit of documents to count.
1985 * @param {boolean} [options.skip=null] The number of documents to skip for the count.
1986 * @param {string} [options.hint=null] An index name hint for the query.
1987 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1988 * @param {number} [options.maxTimeMS=null] Number of miliseconds to wait before aborting the query.
1989 * @param {Collection~countCallback} [callback] The command result callback
1990 * @return {Promise} returns Promise if no callback passed
1992 Collection.prototype.count = function(query, options, callback) {
1994 var args = Array.prototype.slice.call(arguments, 0);
1995 callback = args.pop();
1996 if(typeof callback != 'function') args.push(callback);
1997 var queryOption = args.length ? args.shift() || {} : {};
1998 var optionsOption = args.length ? args.shift() || {} : {};
2000 // Execute using callback
2001 if(typeof callback == 'function') return count(self, queryOption, optionsOption, callback);
2003 // Check if query is empty
2004 query = query || {};
2005 options = options || {};
2008 return new this.s.promiseLibrary(function(resolve, reject) {
2009 count(self, query, options, function(err, r) {
2010 if(err) return reject(err);
2016 var count = function(self, query, options, callback) {
2017 var skip = options.skip;
2018 var limit = options.limit;
2019 var hint = options.hint;
2020 var maxTimeMS = options.maxTimeMS;
2024 'count': self.s.name, 'query': query
2027 // Add limit, skip and maxTimeMS if defined
2028 if(typeof skip == 'number') cmd.skip = skip;
2029 if(typeof limit == 'number') cmd.limit = limit;
2030 if(typeof maxTimeMS == 'number') cmd.maxTimeMS = maxTimeMS;
2031 if(hint) options.hint = hint;
2033 options = shallowClone(options);
2034 // Ensure we have the right read preference inheritance
2035 options = getReadPreference(self, options, self.s.db, self);
2037 // Do we have a readConcern specified
2038 if(self.s.readConcern) {
2039 cmd.readConcern = self.s.readConcern;
2042 // Have we specified collation
2043 decorateWithCollation(cmd, self, options);
2046 self.s.db.command(cmd, options, function(err, result) {
2047 if(err) return handleCallback(callback, err);
2048 handleCallback(callback, null, result.n);
2052 define.classMethod('count', {callback: true, promise:true});
2055 * The distinct command returns returns a list of distinct values for the given key across a collection.
2057 * @param {string} key Field of the document to find distinct values for.
2058 * @param {object} query The query for filtering the set of documents to which we apply the distinct filter.
2059 * @param {object} [options=null] Optional settings.
2060 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2061 * @param {number} [options.maxTimeMS=null] Number of miliseconds to wait before aborting the query.
2062 * @param {Collection~resultCallback} [callback] The command result callback
2063 * @return {Promise} returns Promise if no callback passed
2065 Collection.prototype.distinct = function(key, query, options, callback) {
2067 var args = Array.prototype.slice.call(arguments, 1);
2068 callback = args.pop();
2069 if(typeof callback != 'function') args.push(callback);
2070 var queryOption = args.length ? args.shift() || {} : {};
2071 var optionsOption = args.length ? args.shift() || {} : {};
2073 // Execute using callback
2074 if(typeof callback == 'function') return distinct(self, key, queryOption, optionsOption, callback);
2076 // Ensure the query and options are set
2077 query = query || {};
2078 options = options || {};
2081 return new this.s.promiseLibrary(function(resolve, reject) {
2082 distinct(self, key, query, options, function(err, r) {
2083 if(err) return reject(err);
2089 var distinct = function(self, key, query, options, callback) {
2091 var maxTimeMS = options.maxTimeMS;
2095 'distinct': self.s.name, 'key': key, 'query': query
2098 options = shallowClone(options);
2099 // Ensure we have the right read preference inheritance
2100 options = getReadPreference(self, options, self.s.db, self);
2102 // Add maxTimeMS if defined
2103 if(typeof maxTimeMS == 'number')
2104 cmd.maxTimeMS = maxTimeMS;
2106 // Do we have a readConcern specified
2107 if(self.s.readConcern) {
2108 cmd.readConcern = self.s.readConcern;
2111 // Have we specified collation
2112 decorateWithCollation(cmd, self, options);
2114 // Execute the command
2115 self.s.db.command(cmd, options, function(err, result) {
2116 if(err) return handleCallback(callback, err);
2117 handleCallback(callback, null, result.values);
2121 define.classMethod('distinct', {callback: true, promise:true});
2124 * Retrieve all the indexes on the collection.
2126 * @param {Collection~resultCallback} [callback] The command result callback
2127 * @return {Promise} returns Promise if no callback passed
2129 Collection.prototype.indexes = function(callback) {
2131 // Execute using callback
2132 if(typeof callback == 'function') return indexes(self, callback);
2135 return new this.s.promiseLibrary(function(resolve, reject) {
2136 indexes(self, function(err, r) {
2137 if(err) return reject(err);
2143 var indexes = function(self, callback) {
2144 self.s.db.indexInformation(self.s.name, {full:true}, callback);
2147 define.classMethod('indexes', {callback: true, promise:true});
2150 * Get all the collection statistics.
2153 * @param {object} [options=null] Optional settings.
2154 * @param {number} [options.scale=null] Divide the returned sizes by scale value.
2155 * @param {Collection~resultCallback} [callback] The collection result callback
2156 * @return {Promise} returns Promise if no callback passed
2158 Collection.prototype.stats = function(options, callback) {
2160 var args = Array.prototype.slice.call(arguments, 0);
2161 callback = args.pop();
2162 if(typeof callback != 'function') args.push(callback);
2163 // Fetch all commands
2164 options = args.length ? args.shift() || {} : {};
2166 // Execute using callback
2167 if(typeof callback == 'function') return stats(self, options, callback);
2170 return new this.s.promiseLibrary(function(resolve, reject) {
2171 stats(self, options, function(err, r) {
2172 if(err) return reject(err);
2178 var stats = function(self, options, callback) {
2179 // Build command object
2180 var commandObject = {
2181 collStats:self.s.name
2184 // Check if we have the scale value
2185 if(options['scale'] != null) commandObject['scale'] = options['scale'];
2187 options = shallowClone(options);
2188 // Ensure we have the right read preference inheritance
2189 options = getReadPreference(self, options, self.s.db, self);
2191 // Execute the command
2192 self.s.db.command(commandObject, options, callback);
2195 define.classMethod('stats', {callback: true, promise:true});
2198 * @typedef {Object} Collection~findAndModifyWriteOpResult
2199 * @property {object} value Document returned from findAndModify command.
2200 * @property {object} lastErrorObject The raw lastErrorObject returned from the command.
2201 * @property {Number} ok Is 1 if the command executed correctly.
2205 * The callback format for inserts
2206 * @callback Collection~findAndModifyCallback
2207 * @param {MongoError} error An error instance representing the error during the execution.
2208 * @param {Collection~findAndModifyWriteOpResult} result The result object if the command was executed successfully.
2212 * Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation.
2215 * @param {object} filter Document selection filter.
2216 * @param {object} [options=null] Optional settings.
2217 * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
2218 * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
2219 * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
2220 * @param {Collection~findAndModifyCallback} [callback] The collection result callback
2221 * @return {Promise} returns Promise if no callback passed
2223 Collection.prototype.findOneAndDelete = function(filter, options, callback) {
2225 if(typeof options == 'function') callback = options, options = {};
2226 options = options || {};
2229 if(filter == null || typeof filter != 'object') throw toError('filter parameter must be an object');
2231 // Execute using callback
2232 if(typeof callback == 'function') return findOneAndDelete(self, filter, options, callback);
2235 return new this.s.promiseLibrary(function(resolve, reject) {
2236 options = options || {};
2238 findOneAndDelete(self, filter, options, function(err, r) {
2239 if(err) return reject(err);
2245 var findOneAndDelete = function(self, filter, options, callback) {
2247 var finalOptions = shallowClone(options);
2248 finalOptions['fields'] = options.projection;
2249 finalOptions['remove'] = true;
2250 // Execute find and Modify
2260 define.classMethod('findOneAndDelete', {callback: true, promise:true});
2263 * Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation.
2266 * @param {object} filter Document selection filter.
2267 * @param {object} replacement Document replacing the matching document.
2268 * @param {object} [options=null] Optional settings.
2269 * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
2270 * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
2271 * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
2272 * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
2273 * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
2274 * @param {Collection~findAndModifyCallback} [callback] The collection result callback
2275 * @return {Promise} returns Promise if no callback passed
2277 Collection.prototype.findOneAndReplace = function(filter, replacement, options, callback) {
2279 if(typeof options == 'function') callback = options, options = {};
2280 options = options || {};
2283 if(filter == null || typeof filter != 'object') throw toError('filter parameter must be an object');
2284 if(replacement == null || typeof replacement != 'object') throw toError('replacement parameter must be an object');
2286 // Execute using callback
2287 if(typeof callback == 'function') return findOneAndReplace(self, filter, replacement, options, callback);
2290 return new this.s.promiseLibrary(function(resolve, reject) {
2291 options = options || {};
2293 findOneAndReplace(self, filter, replacement, options, function(err, r) {
2294 if(err) return reject(err);
2300 var findOneAndReplace = function(self, filter, replacement, options, callback) {
2302 var finalOptions = shallowClone(options);
2303 finalOptions['fields'] = options.projection;
2304 finalOptions['update'] = true;
2305 finalOptions['new'] = typeof options.returnOriginal == 'boolean' ? !options.returnOriginal : false;
2306 finalOptions['upsert'] = typeof options.upsert == 'boolean' ? options.upsert : false;
2308 // Execute findAndModify
2318 define.classMethod('findOneAndReplace', {callback: true, promise:true});
2321 * Find a document and update it in one atomic operation, requires a write lock for the duration of the operation.
2324 * @param {object} filter Document selection filter.
2325 * @param {object} update Update operations to be performed on the document
2326 * @param {object} [options=null] Optional settings.
2327 * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
2328 * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
2329 * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
2330 * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
2331 * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
2332 * @param {Collection~findAndModifyCallback} [callback] The collection result callback
2333 * @return {Promise} returns Promise if no callback passed
2335 Collection.prototype.findOneAndUpdate = function(filter, update, options, callback) {
2337 if(typeof options == 'function') callback = options, options = {};
2338 options = options || {};
2341 if(filter == null || typeof filter != 'object') throw toError('filter parameter must be an object');
2342 if(update == null || typeof update != 'object') throw toError('update parameter must be an object');
2344 // Execute using callback
2345 if(typeof callback == 'function') return findOneAndUpdate(self, filter, update, options, callback);
2348 return new this.s.promiseLibrary(function(resolve, reject) {
2349 options = options || {};
2351 findOneAndUpdate(self, filter, update, options, function(err, r) {
2352 if(err) return reject(err);
2358 var findOneAndUpdate = function(self, filter, update, options, callback) {
2360 var finalOptions = shallowClone(options);
2361 finalOptions['fields'] = options.projection;
2362 finalOptions['update'] = true;
2363 finalOptions['new'] = typeof options.returnOriginal == 'boolean' ? !options.returnOriginal : false;
2364 finalOptions['upsert'] = typeof options.upsert == 'boolean' ? options.upsert : false;
2366 // Execute findAndModify
2376 define.classMethod('findOneAndUpdate', {callback: true, promise:true});
2379 * Find and update a document.
2381 * @param {object} query Query object to locate the object to modify.
2382 * @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
2383 * @param {object} doc The fields/vals to be updated.
2384 * @param {object} [options=null] Optional settings.
2385 * @param {(number|string)} [options.w=null] The write concern.
2386 * @param {number} [options.wtimeout=null] The write concern timeout.
2387 * @param {boolean} [options.j=false] Specify a journal write concern.
2388 * @param {boolean} [options.remove=false] Set to true to remove the object before returning.
2389 * @param {boolean} [options.upsert=false] Perform an upsert operation.
2390 * @param {boolean} [options.new=false] Set to true if you want to return the modified object rather than the original. Ignored for remove.
2391 * @param {object} [options.fields=null] Object containing the field projection for the result returned from the operation.
2392 * @param {Collection~findAndModifyCallback} [callback] The command result callback
2393 * @return {Promise} returns Promise if no callback passed
2394 * @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
2396 Collection.prototype.findAndModify = function(query, sort, doc, options, callback) {
2398 var args = Array.prototype.slice.call(arguments, 1);
2399 callback = args.pop();
2400 if(typeof callback != 'function') args.push(callback);
2401 sort = args.length ? args.shift() || [] : [];
2402 doc = args.length ? args.shift() : null;
2403 options = args.length ? args.shift() || {} : {};
2406 var options = shallowClone(options);
2407 // Force read preference primary
2408 options.readPreference = ReadPreference.PRIMARY;
2410 // Execute using callback
2411 if(typeof callback == 'function') return findAndModify(self, query, sort, doc, options, callback);
2414 return new this.s.promiseLibrary(function(resolve, reject) {
2415 options = options || {};
2417 findAndModify(self, query, sort, doc, options, function(err, r) {
2418 if(err) return reject(err);
2424 var findAndModify = function(self, query, sort, doc, options, callback) {
2425 // Create findAndModify command object
2427 'findandmodify': self.s.name
2431 sort = formattedOrderClause(sort);
2433 queryObject.sort = sort;
2436 queryObject.new = options.new ? true : false;
2437 queryObject.remove = options.remove ? true : false;
2438 queryObject.upsert = options.upsert ? true : false;
2440 if(options.fields) {
2441 queryObject.fields = options.fields;
2444 if(doc && !options.remove) {
2445 queryObject.update = doc;
2448 if(options.maxTimeMS)
2449 queryObject.maxTimeMS = options.maxTimeMS;
2451 // Either use override on the function, or go back to default on either the collection
2453 if(options['serializeFunctions'] != null) {
2454 options['serializeFunctions'] = options['serializeFunctions'];
2456 options['serializeFunctions'] = self.s.serializeFunctions;
2459 // No check on the documents
2460 options.checkKeys = false;
2462 // Get the write concern settings
2463 var finalOptions = writeConcern(options, self.s.db, self, options);
2465 // Decorate the findAndModify command with the write Concern
2466 if(finalOptions.writeConcern) {
2467 queryObject.writeConcern = finalOptions.writeConcern;
2470 // Have we specified bypassDocumentValidation
2471 if(typeof finalOptions.bypassDocumentValidation == 'boolean') {
2472 queryObject.bypassDocumentValidation = finalOptions.bypassDocumentValidation;
2475 // Have we specified collation
2476 decorateWithCollation(queryObject, self, options);
2478 // Execute the command
2479 self.s.db.command(queryObject
2480 , options, function(err, result) {
2481 if(err) return handleCallback(callback, err, null);
2482 return handleCallback(callback, null, result);
2486 define.classMethod('findAndModify', {callback: true, promise:true});
2489 * Find and remove a document.
2491 * @param {object} query Query object to locate the object to modify.
2492 * @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
2493 * @param {object} [options=null] Optional settings.
2494 * @param {(number|string)} [options.w=null] The write concern.
2495 * @param {number} [options.wtimeout=null] The write concern timeout.
2496 * @param {boolean} [options.j=false] Specify a journal write concern.
2497 * @param {Collection~resultCallback} [callback] The command result callback
2498 * @return {Promise} returns Promise if no callback passed
2499 * @deprecated use findOneAndDelete instead
2501 Collection.prototype.findAndRemove = function(query, sort, options, callback) {
2503 var args = Array.prototype.slice.call(arguments, 1);
2504 callback = args.pop();
2505 if(typeof callback != 'function') args.push(callback);
2506 sort = args.length ? args.shift() || [] : [];
2507 options = args.length ? args.shift() || {} : {};
2509 // Execute using callback
2510 if(typeof callback == 'function') return findAndRemove(self, query, sort, options, callback);
2513 return new this.s.promiseLibrary(function(resolve, reject) {
2514 findAndRemove(self, query, sort, options, function(err, r) {
2515 if(err) return reject(err);
2521 var findAndRemove = function(self, query, sort, options, callback) {
2522 // Add the remove option
2523 options['remove'] = true;
2524 // Execute the callback
2525 self.findAndModify(query, sort, null, options, callback);
2528 define.classMethod('findAndRemove', {callback: true, promise:true});
2530 function decorateWithWriteConcern(command, self, options) {
2531 // Do we support collation 3.4 and higher
2532 var capabilities = self.s.topology.capabilities();
2533 // Do we support write concerns 3.4 and higher
2534 if(capabilities && capabilities.commandsTakeWriteConcern) {
2535 // Get the write concern settings
2536 var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
2537 // Add the write concern to the command
2538 if(finalOptions.writeConcern) {
2539 command.writeConcern = finalOptions.writeConcern;
2544 function decorateWithCollation(command, self, options) {
2545 // Do we support collation 3.4 and higher
2546 var capabilities = self.s.topology.capabilities();
2547 // Do we support write concerns 3.4 and higher
2548 if(capabilities && capabilities.commandsTakeCollation) {
2549 if(options.collation && typeof options.collation == 'object') {
2550 command.collation = options.collation;
2556 * Execute an aggregation framework pipeline against the collection, needs MongoDB >= 2.2
2558 * @param {object} pipeline Array containing all the aggregation framework commands for the execution.
2559 * @param {object} [options=null] Optional settings.
2560 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2561 * @param {object} [options.cursor=null] Return the query as cursor, on 2.6 > it returns as a real cursor on pre 2.6 it returns as an emulated cursor.
2562 * @param {number} [options.cursor.batchSize=null] The batchSize for the cursor
2563 * @param {boolean} [options.explain=false] Explain returns the aggregation execution plan (requires mongodb 2.6 >).
2564 * @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 >).
2565 * @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.
2566 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
2567 * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
2568 * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
2569 * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
2570 * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
2571 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
2572 * @param {Collection~resultCallback} callback The command result callback
2573 * @return {(null|AggregationCursor)}
2575 Collection.prototype.aggregate = function(pipeline, options, callback) {
2578 if(Array.isArray(pipeline)) {
2579 // Set up callback if one is provided
2580 if(typeof options == 'function') {
2585 // If we have no options or callback we are doing
2586 // a cursor based aggregation
2587 if(options == null && callback == null) {
2591 // Aggregation pipeline passed as arguments on the method
2592 var args = Array.prototype.slice.call(arguments, 0);
2594 callback = args.pop();
2595 // Get the possible options object
2596 var opts = args[args.length - 1];
2597 // If it contains any of the admissible options pop it of the args
2598 options = opts && (opts.readPreference
2599 || opts.explain || opts.cursor || opts.out
2600 || opts.maxTimeMS || opts.allowDiskUse) ? args.pop() : {};
2601 // Left over arguments is the pipeline
2605 // Ignore readConcern option
2606 var ignoreReadConcern = false;
2608 // Build the command
2609 var command = { aggregate : this.s.name, pipeline : pipeline};
2611 // If out was specified
2612 if(typeof options.out == 'string') {
2613 pipeline.push({$out: options.out});
2614 // Ignore read concern
2615 ignoreReadConcern = true;
2616 } else if(pipeline.length > 0 && pipeline[pipeline.length - 1]['$out']) {
2617 ignoreReadConcern = true;
2620 // Decorate command with writeConcern if out has been specified
2621 if(pipeline.length > 0 && pipeline[pipeline.length - 1]['$out']) {
2622 decorateWithWriteConcern(command, self, options);
2625 // Have we specified collation
2626 decorateWithCollation(command, self, options);
2628 // If we have bypassDocumentValidation set
2629 if(typeof options.bypassDocumentValidation == 'boolean') {
2630 command.bypassDocumentValidation = options.bypassDocumentValidation;
2633 // Do we have a readConcern specified
2634 if(!ignoreReadConcern && this.s.readConcern) {
2635 command.readConcern = this.s.readConcern;
2638 // If we have allowDiskUse defined
2639 if(options.allowDiskUse) command.allowDiskUse = options.allowDiskUse;
2640 if(typeof options.maxTimeMS == 'number') command.maxTimeMS = options.maxTimeMS;
2642 options = shallowClone(options);
2643 // Ensure we have the right read preference inheritance
2644 options = getReadPreference(this, options, this.s.db, this);
2646 // If explain has been specified add it
2647 if(options.explain) command.explain = options.explain;
2649 // Validate that cursor options is valid
2650 if(options.cursor != null && typeof options.cursor != 'object') {
2651 throw toError('cursor options must be an object');
2655 options.promiseLibrary = this.s.promiseLibrary;
2657 // Set the AggregationCursor constructor
2658 options.cursorFactory = AggregationCursor;
2659 if(typeof callback != 'function') {
2660 if(!this.s.topology.capabilities()) {
2661 throw new MongoError('cannot connect to server');
2664 if(this.s.topology.capabilities().hasAggregationCursor) {
2665 options.cursor = options.cursor || { batchSize : 1000 };
2666 command.cursor = options.cursor;
2669 // Allow disk usage command
2670 if(typeof options.allowDiskUse == 'boolean') command.allowDiskUse = options.allowDiskUse;
2671 if(typeof options.maxTimeMS == 'number') command.maxTimeMS = options.maxTimeMS;
2673 // Execute the cursor
2674 return this.s.topology.cursor(this.s.namespace, command, options);
2678 // We do not allow cursor
2679 if(options.cursor) {
2680 return this.s.topology.cursor(this.s.namespace, command, options);
2683 // Execute the command
2684 this.s.db.command(command, options, function(err, result) {
2686 handleCallback(callback, err);
2687 } else if(result['err'] || result['errmsg']) {
2688 handleCallback(callback, toError(result));
2689 } else if(typeof result == 'object' && result['serverPipeline']) {
2690 handleCallback(callback, null, result['serverPipeline']);
2691 } else if(typeof result == 'object' && result['stages']) {
2692 handleCallback(callback, null, result['stages']);
2694 handleCallback(callback, null, result.result);
2699 define.classMethod('aggregate', {callback: true, promise:false});
2702 * The callback format for results
2703 * @callback Collection~parallelCollectionScanCallback
2704 * @param {MongoError} error An error instance representing the error during the execution.
2705 * @param {Cursor[]} cursors A list of cursors returned allowing for parallel reading of collection.
2709 * Return N number of parallel cursors for a collection allowing parallel reading of entire collection. There are
2710 * no ordering guarantees for returned results.
2712 * @param {object} [options=null] Optional settings.
2713 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2714 * @param {number} [options.batchSize=null] Set the batchSize for the getMoreCommand when iterating over the query results.
2715 * @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)
2716 * @param {boolean} [options.raw=false] Return all BSON documents as Raw Buffer documents.
2717 * @param {Collection~parallelCollectionScanCallback} [callback] The command result callback
2718 * @return {Promise} returns Promise if no callback passed
2720 Collection.prototype.parallelCollectionScan = function(options, callback) {
2722 if(typeof options == 'function') callback = options, options = {numCursors: 1};
2723 // Set number of cursors to 1
2724 options.numCursors = options.numCursors || 1;
2725 options.batchSize = options.batchSize || 1000;
2727 options = shallowClone(options);
2728 // Ensure we have the right read preference inheritance
2729 options = getReadPreference(this, options, this.s.db, this);
2731 // Add a promiseLibrary
2732 options.promiseLibrary = this.s.promiseLibrary;
2734 // Execute using callback
2735 if(typeof callback == 'function') return parallelCollectionScan(self, options, callback);
2738 return new this.s.promiseLibrary(function(resolve, reject) {
2739 parallelCollectionScan(self, options, function(err, r) {
2740 if(err) return reject(err);
2746 var parallelCollectionScan = function(self, options, callback) {
2747 // Create command object
2748 var commandObject = {
2749 parallelCollectionScan: self.s.name
2750 , numCursors: options.numCursors
2753 // Do we have a readConcern specified
2754 if(self.s.readConcern) {
2755 commandObject.readConcern = self.s.readConcern;
2758 // Store the raw value
2759 var raw = options.raw;
2760 delete options['raw'];
2762 // Execute the command
2763 self.s.db.command(commandObject, options, function(err, result) {
2764 if(err) return handleCallback(callback, err, null);
2765 if(result == null) return handleCallback(callback, new Error("no result returned for parallelCollectionScan"), null);
2768 // Add the raw back to the option
2769 if(raw) options.raw = raw;
2770 // Create command cursors for each item
2771 for(var i = 0; i < result.cursors.length; i++) {
2772 var rawId = result.cursors[i].cursor.id
2773 // Convert cursorId to Long if needed
2774 var cursorId = typeof rawId == 'number' ? Long.fromNumber(rawId) : rawId;
2776 // Command cursor options
2778 batchSize: options.batchSize
2779 , cursorId: cursorId
2780 , items: result.cursors[i].cursor.firstBatch
2783 // Add a command cursor
2784 cursors.push(self.s.topology.cursor(self.s.namespace, cursorId, options));
2787 handleCallback(callback, null, cursors);
2791 define.classMethod('parallelCollectionScan', {callback: true, promise:true});
2794 * Execute the geoNear command to search for items in the collection
2797 * @param {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
2798 * @param {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
2799 * @param {object} [options=null] Optional settings.
2800 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2801 * @param {number} [options.num=null] Max number of results to return.
2802 * @param {number} [options.minDistance=null] Include results starting at minDistance from a point (2.6 or higher)
2803 * @param {number} [options.maxDistance=null] Include results up to maxDistance from the point.
2804 * @param {number} [options.distanceMultiplier=null] Include a value to multiply the distances with allowing for range conversions.
2805 * @param {object} [options.query=null] Filter the results by a query.
2806 * @param {boolean} [options.spherical=false] Perform query using a spherical model.
2807 * @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.
2808 * @param {boolean} [options.includeLocs=false] Include the location data fields in the top level of the results MongoDB > 2.X.
2809 * @param {Collection~resultCallback} [callback] The command result callback
2810 * @return {Promise} returns Promise if no callback passed
2812 Collection.prototype.geoNear = function(x, y, options, callback) {
2814 var point = typeof(x) == 'object' && x
2815 , args = Array.prototype.slice.call(arguments, point?1:2);
2817 callback = args.pop();
2818 if(typeof callback != 'function') args.push(callback);
2819 // Fetch all commands
2820 options = args.length ? args.shift() || {} : {};
2822 // Execute using callback
2823 if(typeof callback == 'function') return geoNear(self, x, y, point, options, callback);
2826 return new this.s.promiseLibrary(function(resolve, reject) {
2827 geoNear(self, x, y, point, options, function(err, r) {
2828 if(err) return reject(err);
2834 var geoNear = function(self, x, y, point, options, callback) {
2835 // Build command object
2836 var commandObject = {
2837 geoNear:self.s.name,
2838 near: point || [x, y]
2841 options = shallowClone(options);
2842 // Ensure we have the right read preference inheritance
2843 options = getReadPreference(self, options, self.s.db, self);
2845 // Exclude readPreference and existing options to prevent user from
2846 // shooting themselves in the foot
2848 readPreference: true,
2853 // Filter out any excluded objects
2854 commandObject = decorateCommand(commandObject, options, exclude);
2856 // Do we have a readConcern specified
2857 if(self.s.readConcern) {
2858 commandObject.readConcern = self.s.readConcern;
2861 // Have we specified collation
2862 decorateWithCollation(commandObject, self, options);
2864 // Execute the command
2865 self.s.db.command(commandObject, options, function (err, res) {
2866 if(err) return handleCallback(callback, err);
2867 if(res.err || res.errmsg) return handleCallback(callback, toError(res));
2868 // should we only be returning res.results here? Not sure if the user
2869 // should see the other return information
2870 handleCallback(callback, null, res);
2874 define.classMethod('geoNear', {callback: true, promise:true});
2877 * Execute a geo search using a geo haystack index on a collection.
2880 * @param {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
2881 * @param {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
2882 * @param {object} [options=null] Optional settings.
2883 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2884 * @param {number} [options.maxDistance=null] Include results up to maxDistance from the point.
2885 * @param {object} [options.search=null] Filter the results by a query.
2886 * @param {number} [options.limit=false] Max number of results to return.
2887 * @param {Collection~resultCallback} [callback] The command result callback
2888 * @return {Promise} returns Promise if no callback passed
2890 Collection.prototype.geoHaystackSearch = function(x, y, options, callback) {
2892 var args = Array.prototype.slice.call(arguments, 2);
2893 callback = args.pop();
2894 if(typeof callback != 'function') args.push(callback);
2895 // Fetch all commands
2896 options = args.length ? args.shift() || {} : {};
2898 // Execute using callback
2899 if(typeof callback == 'function') return geoHaystackSearch(self, x, y, options, callback);
2902 return new this.s.promiseLibrary(function(resolve, reject) {
2903 geoHaystackSearch(self, x, y, options, function(err, r) {
2904 if(err) return reject(err);
2910 var geoHaystackSearch = function(self, x, y, options, callback) {
2911 // Build command object
2912 var commandObject = {
2913 geoSearch: self.s.name,
2917 // Remove read preference from hash if it exists
2918 commandObject = decorateCommand(commandObject, options, {readPreference: true});
2920 options = shallowClone(options);
2921 // Ensure we have the right read preference inheritance
2922 options = getReadPreference(self, options, self.s.db, self);
2924 // Do we have a readConcern specified
2925 if(self.s.readConcern) {
2926 commandObject.readConcern = self.s.readConcern;
2929 // Execute the command
2930 self.s.db.command(commandObject, options, function (err, res) {
2931 if(err) return handleCallback(callback, err);
2932 if(res.err || res.errmsg) handleCallback(callback, utils.toError(res));
2933 // should we only be returning res.results here? Not sure if the user
2934 // should see the other return information
2935 handleCallback(callback, null, res);
2939 define.classMethod('geoHaystackSearch', {callback: true, promise:true});
2942 * Group function helper
2945 // var groupFunction = function () {
2946 // var c = db[ns].find(condition);
2947 // var map = new Map();
2948 // var reduce_function = reduce;
2950 // while (c.hasNext()) {
2951 // var obj = c.next();
2954 // for (var i = 0, len = keys.length; i < len; ++i) {
2959 // var aggObj = map.get(key);
2961 // if (aggObj == null) {
2962 // var newObj = Object.extend({}, key);
2963 // aggObj = Object.extend(newObj, initial);
2964 // map.put(key, aggObj);
2967 // reduce_function(obj, aggObj);
2970 // return { "result": map.values() };
2972 var groupFunction = 'function () {\nvar c = db[ns].find(condition);\nvar map = new Map();\nvar reduce_function = reduce;\n\nwhile (c.hasNext()) {\nvar obj = c.next();\nvar key = {};\n\nfor (var i = 0, len = keys.length; i < len; ++i) {\nvar k = keys[i];\nkey[k] = obj[k];\n}\n\nvar aggObj = map.get(key);\n\nif (aggObj == null) {\nvar newObj = Object.extend({}, key);\naggObj = Object.extend(newObj, initial);\nmap.put(key, aggObj);\n}\n\nreduce_function(obj, aggObj);\n}\n\nreturn { "result": map.values() };\n}';
2975 * Run a group command across a collection
2978 * @param {(object|array|function|code)} keys An object, array or function expressing the keys to group by.
2979 * @param {object} condition An optional condition that must be true for a row to be considered.
2980 * @param {object} initial Initial value of the aggregation counter object.
2981 * @param {(function|Code)} reduce The reduce function aggregates (reduces) the objects iterated
2982 * @param {(function|Code)} finalize An optional function to be run on each item in the result set just before the item is returned.
2983 * @param {boolean} command Specify if you wish to run using the internal group command or using eval, default is true.
2984 * @param {object} [options=null] Optional settings.
2985 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
2986 * @param {Collection~resultCallback} [callback] The command result callback
2987 * @return {Promise} returns Promise if no callback passed
2989 Collection.prototype.group = function(keys, condition, initial, reduce, finalize, command, options, callback) {
2991 var args = Array.prototype.slice.call(arguments, 3);
2992 callback = args.pop();
2993 if(typeof callback != 'function') args.push(callback);
2994 // Fetch all commands
2995 reduce = args.length ? args.shift() : null;
2996 finalize = args.length ? args.shift() : null;
2997 command = args.length ? args.shift() : null;
2998 options = args.length ? args.shift() || {} : {};
3000 // Make sure we are backward compatible
3001 if(!(typeof finalize == 'function')) {
3006 if (!Array.isArray(keys) && keys instanceof Object && typeof(keys) !== 'function' && !(keys instanceof Code)) {
3007 keys = Object.keys(keys);
3010 if(typeof reduce === 'function') {
3011 reduce = reduce.toString();
3014 if(typeof finalize === 'function') {
3015 finalize = finalize.toString();
3018 // Set up the command as default
3019 command = command == null ? true : command;
3021 // Execute using callback
3022 if(typeof callback == 'function') return group(self, keys, condition, initial, reduce, finalize, command, options, callback);
3024 return new this.s.promiseLibrary(function(resolve, reject) {
3025 group(self, keys, condition, initial, reduce, finalize, command, options, function(err, r) {
3026 if(err) return reject(err);
3032 var group = function(self, keys, condition, initial, reduce, finalize, command, options, callback) {
3033 // Execute using the command
3035 var reduceFunction = reduce instanceof Code
3042 , '$reduce': reduceFunction
3044 , 'initial': initial
3049 // if finalize is defined
3050 if(finalize != null) selector.group['finalize'] = finalize;
3051 // Set up group selector
3052 if ('function' === typeof keys || keys instanceof Code) {
3053 selector.group.$keyf = keys instanceof Code
3058 keys.forEach(function (key) {
3061 selector.group.key = hash;
3064 options = shallowClone(options);
3065 // Ensure we have the right read preference inheritance
3066 options = getReadPreference(self, options, self.s.db, self);
3068 // Do we have a readConcern specified
3069 if(self.s.readConcern) {
3070 selector.readConcern = self.s.readConcern;
3073 // Have we specified collation
3074 decorateWithCollation(selector, self, options);
3077 self.s.db.command(selector, options, function(err, result) {
3078 if(err) return handleCallback(callback, err, null);
3079 handleCallback(callback, null, result.retval);
3082 // Create execution scope
3083 var scope = reduce != null && reduce instanceof Code
3087 scope.ns = self.s.name;
3089 scope.condition = condition;
3090 scope.initial = initial;
3092 // Pass in the function text to execute within mongodb.
3093 var groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';');
3095 self.s.db.eval(new Code(groupfn, scope), function (err, results) {
3096 if (err) return handleCallback(callback, err, null);
3097 handleCallback(callback, null, results.result || results);
3102 define.classMethod('group', {callback: true, promise:true});
3105 * Functions that are passed as scope args must
3106 * be converted to Code instances.
3109 function processScope (scope) {
3110 if(!isObject(scope) || scope instanceof ObjectID) {
3114 var keys = Object.keys(scope);
3115 var i = keys.length;
3121 if ('function' == typeof scope[key]) {
3122 new_scope[key] = new Code(String(scope[key]));
3124 new_scope[key] = processScope(scope[key]);
3132 * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
3135 * @param {(function|string)} map The mapping function.
3136 * @param {(function|string)} reduce The reduce function.
3137 * @param {object} [options=null] Optional settings.
3138 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
3139 * @param {object} [options.out=null] Sets the output target for the map reduce job. *{inline:1} | {replace:'collectionName'} | {merge:'collectionName'} | {reduce:'collectionName'}*
3140 * @param {object} [options.query=null] Query filter object.
3141 * @param {object} [options.sort=null] Sorts the input objects using this key. Useful for optimization, like sorting by the emit key for fewer reduces.
3142 * @param {number} [options.limit=null] Number of objects to return from collection.
3143 * @param {boolean} [options.keeptemp=false] Keep temporary data.
3144 * @param {(function|string)} [options.finalize=null] Finalize function.
3145 * @param {object} [options.scope=null] Can pass in variables that can be access from map/reduce/finalize.
3146 * @param {boolean} [options.jsMode=false] It is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X.
3147 * @param {boolean} [options.verbose=false] Provide statistics on job execution time.
3148 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
3149 * @param {Collection~resultCallback} [callback] The command result callback
3150 * @throws {MongoError}
3151 * @return {Promise} returns Promise if no callback passed
3153 Collection.prototype.mapReduce = function(map, reduce, options, callback) {
3155 if('function' === typeof options) callback = options, options = {};
3156 // Out must allways be defined (make sure we don't break weirdly on pre 1.8+ servers)
3157 if(null == options.out) {
3158 throw new Error("the out option parameter must be defined, see mongodb docs for possible values");
3161 if('function' === typeof map) {
3162 map = map.toString();
3165 if('function' === typeof reduce) {
3166 reduce = reduce.toString();
3169 if('function' === typeof options.finalize) {
3170 options.finalize = options.finalize.toString();
3173 // Execute using callback
3174 if(typeof callback == 'function') return mapReduce(self, map, reduce, options, callback);
3177 return new this.s.promiseLibrary(function(resolve, reject) {
3178 mapReduce(self, map, reduce, options, function(err, r, r1) {
3179 if(err) return reject(err);
3180 if(!r1) return resolve(r);
3181 resolve({results: r, stats: r1});
3186 var mapReduce = function(self, map, reduce, options, callback) {
3187 var mapCommandHash = {
3188 mapreduce: self.s.name
3193 // Add any other options passed in
3194 for(var n in options) {
3196 mapCommandHash[n] = processScope(options[n]);
3198 mapCommandHash[n] = options[n];
3202 options = shallowClone(options);
3203 // Ensure we have the right read preference inheritance
3204 options = getReadPreference(self, options, self.s.db, self);
3206 // If we have a read preference and inline is not set as output fail hard
3207 if((options.readPreference != false && options.readPreference != 'primary')
3208 && options['out'] && (options['out'].inline != 1 && options['out'] != 'inline')) {
3209 // Force readPreference to primary
3210 options.readPreference = 'primary';
3211 // Decorate command with writeConcern if supported
3212 decorateWithWriteConcern(mapCommandHash, self, options);
3213 } else if(self.s.readConcern) {
3214 mapCommandHash.readConcern = self.s.readConcern;
3217 // Is bypassDocumentValidation specified
3218 if(typeof options.bypassDocumentValidation == 'boolean') {
3219 mapCommandHash.bypassDocumentValidation = options.bypassDocumentValidation;
3222 // Have we specified collation
3223 decorateWithCollation(mapCommandHash, self, options);
3226 self.s.db.command(mapCommandHash, {readPreference:options.readPreference}, function (err, result) {
3227 if(err) return handleCallback(callback, err);
3228 // Check if we have an error
3229 if(1 != result.ok || result.err || result.errmsg) {
3230 return handleCallback(callback, toError(result));
3233 // Create statistics value
3235 if(result.timeMillis) stats['processtime'] = result.timeMillis;
3236 if(result.counts) stats['counts'] = result.counts;
3237 if(result.timing) stats['timing'] = result.timing;
3239 // invoked with inline?
3240 if(result.results) {
3241 // If we wish for no verbosity
3242 if(options['verbose'] == null || !options['verbose']) {
3243 return handleCallback(callback, null, result.results);
3246 return handleCallback(callback, null, result.results, stats);
3249 // The returned collection
3250 var collection = null;
3252 // If we have an object it's a different db
3253 if(result.result != null && typeof result.result == 'object') {
3254 var doc = result.result;
3255 collection = self.s.db.db(doc.db).collection(doc.collection);
3257 // Create a collection object that wraps the result collection
3258 collection = self.s.db.collection(result.result)
3261 // If we wish for no verbosity
3262 if(options['verbose'] == null || !options['verbose']) {
3263 return handleCallback(callback, err, collection);
3266 // Return stats as third set of values
3267 handleCallback(callback, err, collection, stats);
3271 define.classMethod('mapReduce', {callback: true, promise:true});
3274 * Initiate a Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order.
3277 * @param {object} [options=null] Optional settings.
3278 * @param {(number|string)} [options.w=null] The write concern.
3279 * @param {number} [options.wtimeout=null] The write concern timeout.
3280 * @param {boolean} [options.j=false] Specify a journal write concern.
3281 * @return {UnorderedBulkOperation}
3283 Collection.prototype.initializeUnorderedBulkOp = function(options) {
3284 options = options || {};
3285 options.promiseLibrary = this.s.promiseLibrary;
3286 return unordered(this.s.topology, this, options);
3289 define.classMethod('initializeUnorderedBulkOp', {callback: false, promise:false, returns: [ordered.UnorderedBulkOperation]});
3292 * 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.
3295 * @param {object} [options=null] Optional settings.
3296 * @param {(number|string)} [options.w=null] The write concern.
3297 * @param {number} [options.wtimeout=null] The write concern timeout.
3298 * @param {boolean} [options.j=false] Specify a journal write concern.
3299 * @param {OrderedBulkOperation} callback The command result callback
3302 Collection.prototype.initializeOrderedBulkOp = function(options) {
3303 options = options || {};
3304 options.promiseLibrary = this.s.promiseLibrary;
3305 return ordered(this.s.topology, this, options);
3308 define.classMethod('initializeOrderedBulkOp', {callback: false, promise:false, returns: [ordered.OrderedBulkOperation]});
3310 // Get write concern
3311 var writeConcern = function(target, db, col, options) {
3312 if(options.w != null || options.j != null || options.fsync != null) {
3314 if(options.w != null) opts.w = options.w;
3315 if(options.wtimeout != null) opts.wtimeout = options.wtimeout;
3316 if(options.j != null) opts.j = options.j;
3317 if(options.fsync != null) opts.fsync = options.fsync;
3318 target.writeConcern = opts;
3319 } else if(col.writeConcern.w != null || col.writeConcern.j != null || col.writeConcern.fsync != null) {
3320 target.writeConcern = col.writeConcern;
3321 } else if(db.writeConcern.w != null || db.writeConcern.j != null || db.writeConcern.fsync != null) {
3322 target.writeConcern = db.writeConcern;
3328 // Figure out the read preference
3329 var getReadPreference = function(self, options, db, coll) {
3331 if(options.readPreference) {
3332 r = options.readPreference
3333 } else if(self.s.readPreference) {
3334 r = self.s.readPreference
3335 } else if(db.s.readPreference) {
3336 r = db.s.readPreference;
3339 if(r instanceof ReadPreference) {
3340 options.readPreference = new CoreReadPreference(r.mode, r.tags, {maxStalenessMS: r.maxStalenessMS});
3341 } else if(typeof r == 'string') {
3342 options.readPreference = new CoreReadPreference(r);
3343 } else if(r && !(r instanceof ReadPreference) && typeof r == 'object') {
3344 var mode = r.mode || r.preference;
3345 if (mode && typeof mode == 'string') {
3346 options.readPreference = new CoreReadPreference(mode, r.tags, {maxStalenessMS: r.maxStalenessMS});
3353 var testForFields = {
3354 limit: 1, sort: 1, fields:1, skip: 1, hint: 1, explain: 1, snapshot: 1, timeout: 1, tailable: 1, tailableRetryInterval: 1
3355 , numberOfRetries: 1, awaitdata: 1, awaitData: 1, exhaust: 1, batchSize: 1, returnKey: 1, maxScan: 1, min: 1, max: 1, showDiskLoc: 1
3356 , comment: 1, raw: 1, readPreference: 1, partial: 1, read: 1, dbName: 1, oplogReplay: 1, connection: 1, maxTimeMS: 1, transforms: 1
3360 module.exports = Collection;