PageRenderTime 106ms CodeModel.GetById 14ms app.highlight 78ms RepoModel.GetById 1ms app.codeStats 1ms

/node_modules/mongoose/node_modules/mongodb/lib/collection.js

https://bitbucket.org/coleman333/smartsite
JavaScript | 3143 lines | 1548 code | 426 blank | 1169 comment | 525 complexity | cd07cd466b16d64808c290bfbd7f811e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1'use strict';
   2
   3var 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('mongodb-core').ReadPreference,
  18  CommandCursor = require('./command_cursor'),
  19  Define = require('./metadata'),
  20  Cursor = require('./cursor'),
  21  unordered = require('./bulk/unordered'),
  22  ordered = require('./bulk/ordered'),
  23  ChangeStream = require('./change_stream'),
  24  executeOperation = require('./utils').executeOperation;
  25
  26/**
  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.
  29 *
  30 * **COLLECTION Cannot directly be instantiated**
  31 * @example
  32 * const MongoClient = require('mongodb').MongoClient;
  33 * const test = require('assert');
  34 * // Connection url
  35 * const url = 'mongodb://localhost:27017';
  36 * // Database Name
  37 * const dbName = 'test';
  38 * // Connect using MongoClient
  39 * MongoClient.connect(url, function(err, client) {
  40 *   // Create a collection we want to drop later
  41 *   const col = client.db(dbName).collection('createIndexExample1');
  42 *   // Show that duplicate records got dropped
  43 *   col.find({}).toArray(function(err, items) {
  44 *     test.equal(null, err);
  45 *     test.equal(4, items.length);
  46 *     client.close();
  47 *   });
  48 * });
  49 */
  50
  51var mergeKeys = ['readPreference', 'ignoreUndefined'];
  52
  53/**
  54 * Create a new Collection instance (INTERNAL TYPE, do not instantiate directly)
  55 * @class
  56 * @property {string} collectionName Get the collection name.
  57 * @property {string} namespace Get the full collection namespace.
  58 * @property {object} writeConcern The current write concern values.
  59 * @property {object} readConcern The current read concern values.
  60 * @property {object} hint Get current index hint for collection.
  61 * @return {Collection} a Collection instance.
  62 */
  63var Collection = function(db, topology, dbName, name, pkFactory, options) {
  64  checkCollectionName(name);
  65
  66  // Unpack variables
  67  var internalHint = null;
  68  var slaveOk = options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk;
  69  var serializeFunctions =
  70    options == null || options.serializeFunctions == null
  71      ? db.s.options.serializeFunctions
  72      : options.serializeFunctions;
  73  var raw = options == null || options.raw == null ? db.s.options.raw : options.raw;
  74  var promoteLongs =
  75    options == null || options.promoteLongs == null
  76      ? db.s.options.promoteLongs
  77      : options.promoteLongs;
  78  var promoteValues =
  79    options == null || options.promoteValues == null
  80      ? db.s.options.promoteValues
  81      : options.promoteValues;
  82  var promoteBuffers =
  83    options == null || options.promoteBuffers == null
  84      ? db.s.options.promoteBuffers
  85      : options.promoteBuffers;
  86  var readPreference = null;
  87  var collectionHint = null;
  88  var namespace = f('%s.%s', dbName, name);
  89
  90  // Get the promiseLibrary
  91  var promiseLibrary = options.promiseLibrary || Promise;
  92
  93  // Assign the right collection level readPreference
  94  if (options && options.readPreference) {
  95    readPreference = options.readPreference;
  96  } else if (db.options.readPreference) {
  97    readPreference = db.options.readPreference;
  98  }
  99
 100  // Set custom primary key factory if provided
 101  pkFactory = pkFactory == null ? ObjectID : pkFactory;
 102
 103  // Internal state
 104  this.s = {
 105    // Set custom primary key factory if provided
 106    pkFactory: pkFactory,
 107    // Db
 108    db: db,
 109    // Topology
 110    topology: topology,
 111    // dbName
 112    dbName: dbName,
 113    // Options
 114    options: options,
 115    // Namespace
 116    namespace: namespace,
 117    // Read preference
 118    readPreference: readPreference,
 119    // SlaveOK
 120    slaveOk: slaveOk,
 121    // Serialize functions
 122    serializeFunctions: serializeFunctions,
 123    // Raw
 124    raw: raw,
 125    // promoteLongs
 126    promoteLongs: promoteLongs,
 127    // promoteValues
 128    promoteValues: promoteValues,
 129    // promoteBuffers
 130    promoteBuffers: promoteBuffers,
 131    // internalHint
 132    internalHint: internalHint,
 133    // collectionHint
 134    collectionHint: collectionHint,
 135    // Name
 136    name: name,
 137    // Promise library
 138    promiseLibrary: promiseLibrary,
 139    // Read Concern
 140    readConcern: options.readConcern
 141  };
 142};
 143
 144var define = (Collection.define = new Define('Collection', Collection, false));
 145
 146Object.defineProperty(Collection.prototype, 'dbName', {
 147  enumerable: true,
 148  get: function() {
 149    return this.s.dbName;
 150  }
 151});
 152
 153Object.defineProperty(Collection.prototype, 'collectionName', {
 154  enumerable: true,
 155  get: function() {
 156    return this.s.name;
 157  }
 158});
 159
 160Object.defineProperty(Collection.prototype, 'namespace', {
 161  enumerable: true,
 162  get: function() {
 163    return this.s.namespace;
 164  }
 165});
 166
 167Object.defineProperty(Collection.prototype, 'readConcern', {
 168  enumerable: true,
 169  get: function() {
 170    return this.s.readConcern || { level: 'local' };
 171  }
 172});
 173
 174Object.defineProperty(Collection.prototype, 'writeConcern', {
 175  enumerable: true,
 176  get: function() {
 177    var ops = {};
 178    if (this.s.options.w != null) ops.w = this.s.options.w;
 179    if (this.s.options.j != null) ops.j = this.s.options.j;
 180    if (this.s.options.fsync != null) ops.fsync = this.s.options.fsync;
 181    if (this.s.options.wtimeout != null) ops.wtimeout = this.s.options.wtimeout;
 182    return ops;
 183  }
 184});
 185
 186/**
 187 * @ignore
 188 */
 189Object.defineProperty(Collection.prototype, 'hint', {
 190  enumerable: true,
 191  get: function() {
 192    return this.s.collectionHint;
 193  },
 194  set: function(v) {
 195    this.s.collectionHint = normalizeHintField(v);
 196  }
 197});
 198
 199/**
 200 * Creates a cursor for a query that can be used to iterate over results from MongoDB
 201 * @method
 202 * @param {object} [query={}] The cursor query object.
 203 * @param {object} [options=null] Optional settings.
 204 * @param {number} [options.limit=0] Sets the limit of documents returned in the query.
 205 * @param {(array|object)} [options.sort=null] Set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
 206 * @param {object} [options.projection=null] The fields to return in the query. Object of fields to include or exclude (not both), {'a':1}
 207 * @param {object} [options.fields=null] **Deprecated** Use `options.projection` instead
 208 * @param {number} [options.skip=0] Set to skip N documents ahead in your query (useful for pagination).
 209 * @param {Object} [options.hint=null] Tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
 210 * @param {boolean} [options.explain=false] Explain the query instead of returning the data.
 211 * @param {boolean} [options.snapshot=false] Snapshot query.
 212 * @param {boolean} [options.timeout=false] Specify if the cursor can timeout.
 213 * @param {boolean} [options.tailable=false] Specify if the cursor is tailable.
 214 * @param {number} [options.batchSize=0] Set the batchSize for the getMoreCommand when iterating over the query results.
 215 * @param {boolean} [options.returnKey=false] Only return the index key.
 216 * @param {number} [options.maxScan=null] Limit the number of items to scan.
 217 * @param {number} [options.min=null] Set index bounds.
 218 * @param {number} [options.max=null] Set index bounds.
 219 * @param {boolean} [options.showDiskLoc=false] Show disk location of results.
 220 * @param {string} [options.comment=null] You can put a $comment field on a query to make looking in the profiler logs simpler.
 221 * @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
 222 * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
 223 * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
 224 * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
 225 * @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
 226 * @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
 227 * @param {number} [options.maxTimeMS=null] Number of miliseconds to wait before aborting the query.
 228 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
 229 * @param {ClientSession} [options.session] optional session to use for this operation
 230 * @throws {MongoError}
 231 * @return {Cursor}
 232 */
 233Collection.prototype.find = function(query, options, callback) {
 234  let selector = query;
 235  // figuring out arguments
 236  if (typeof callback !== 'function') {
 237    if (typeof options === 'function') {
 238      callback = options;
 239      options = undefined;
 240    } else if (options == null) {
 241      callback = typeof selector === 'function' ? selector : undefined;
 242      selector = typeof selector === 'object' ? selector : undefined;
 243    }
 244  }
 245
 246  // Ensure selector is not null
 247  selector = selector == null ? {} : selector;
 248  // Validate correctness off the selector
 249  var object = selector;
 250  if (Buffer.isBuffer(object)) {
 251    var object_size = object[0] | (object[1] << 8) | (object[2] << 16) | (object[3] << 24);
 252    if (object_size !== object.length) {
 253      var error = new Error(
 254        'query selector raw message size does not match message header size [' +
 255          object.length +
 256          '] != [' +
 257          object_size +
 258          ']'
 259      );
 260      error.name = 'MongoError';
 261      throw error;
 262    }
 263  }
 264
 265  // Check special case where we are using an objectId
 266  if (selector != null && selector._bsontype === 'ObjectID') {
 267    selector = { _id: selector };
 268  }
 269
 270  if (!options) options = {};
 271
 272  let projection = options.projection || options.fields;
 273
 274  if (projection && !Buffer.isBuffer(projection) && Array.isArray(projection)) {
 275    projection = projection.length
 276      ? projection.reduce((result, field) => {
 277          result[field] = 1;
 278          return result;
 279        }, {})
 280      : { _id: 1 };
 281  }
 282
 283  var newOptions = {};
 284
 285  // Make a shallow copy of the collection options
 286  for (var key in this.s.options) {
 287    if (mergeKeys.indexOf(key) !== -1) {
 288      newOptions[key] = this.s.options[key];
 289    }
 290  }
 291
 292  // Make a shallow copy of options
 293  for (var optKey in options) {
 294    newOptions[optKey] = options[optKey];
 295  }
 296
 297  // Unpack options
 298  newOptions.skip = options.skip ? options.skip : 0;
 299  newOptions.limit = options.limit ? options.limit : 0;
 300  newOptions.raw = typeof options.raw === 'boolean' ? options.raw : this.s.raw;
 301  newOptions.hint = options.hint != null ? normalizeHintField(options.hint) : this.s.collectionHint;
 302  newOptions.timeout = typeof options.timeout === 'undefined' ? undefined : options.timeout;
 303  // // If we have overridden slaveOk otherwise use the default db setting
 304  newOptions.slaveOk = options.slaveOk != null ? options.slaveOk : this.s.db.slaveOk;
 305
 306  // Add read preference if needed
 307  newOptions = getReadPreference(this, newOptions, this.s.db);
 308
 309  // Set slave ok to true if read preference different from primary
 310  if (
 311    newOptions.readPreference != null &&
 312    (newOptions.readPreference !== 'primary' || newOptions.readPreference.mode !== 'primary')
 313  ) {
 314    newOptions.slaveOk = true;
 315  }
 316
 317  // Ensure the query is an object
 318  if (selector != null && typeof selector !== 'object') {
 319    throw MongoError.create({ message: 'query selector must be an object', driver: true });
 320  }
 321
 322  // Build the find command
 323  var findCommand = {
 324    find: this.s.namespace,
 325    limit: newOptions.limit,
 326    skip: newOptions.skip,
 327    query: selector
 328  };
 329
 330  // Ensure we use the right await data option
 331  if (typeof newOptions.awaitdata === 'boolean') {
 332    newOptions.awaitData = newOptions.awaitdata;
 333  }
 334
 335  // Translate to new command option noCursorTimeout
 336  if (typeof newOptions.timeout === 'boolean') newOptions.noCursorTimeout = newOptions.timeout;
 337
 338  // Merge in options to command
 339  for (var name in newOptions) {
 340    if (newOptions[name] != null && name !== 'session') {
 341      findCommand[name] = newOptions[name];
 342    }
 343  }
 344
 345  if (projection) findCommand.fields = projection;
 346
 347  // Add db object to the new options
 348  newOptions.db = this.s.db;
 349
 350  // Add the promise library
 351  newOptions.promiseLibrary = this.s.promiseLibrary;
 352
 353  // Set raw if available at collection level
 354  if (newOptions.raw == null && typeof this.s.raw === 'boolean') newOptions.raw = this.s.raw;
 355  // Set promoteLongs if available at collection level
 356  if (newOptions.promoteLongs == null && typeof this.s.promoteLongs === 'boolean')
 357    newOptions.promoteLongs = this.s.promoteLongs;
 358  if (newOptions.promoteValues == null && typeof this.s.promoteValues === 'boolean')
 359    newOptions.promoteValues = this.s.promoteValues;
 360  if (newOptions.promoteBuffers == null && typeof this.s.promoteBuffers === 'boolean')
 361    newOptions.promoteBuffers = this.s.promoteBuffers;
 362
 363  // Sort options
 364  if (findCommand.sort) {
 365    findCommand.sort = formattedOrderClause(findCommand.sort);
 366  }
 367
 368  // Set the readConcern
 369  decorateWithReadConcern(findCommand, this, options);
 370
 371  // Decorate find command with collation options
 372  decorateWithCollation(findCommand, this, options);
 373
 374  // Create the cursor
 375  if (typeof callback === 'function')
 376    return handleCallback(
 377      callback,
 378      null,
 379      this.s.topology.cursor(this.s.namespace, findCommand, newOptions)
 380    );
 381  return this.s.topology.cursor(this.s.namespace, findCommand, newOptions);
 382};
 383
 384define.classMethod('find', { callback: false, promise: false, returns: [Cursor] });
 385
 386/**
 387 * Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,
 388 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
 389 * can be overridden by setting the **forceServerObjectId** flag.
 390 *
 391 * @method
 392 * @param {object} doc Document to insert.
 393 * @param {object} [options=null] Optional settings.
 394 * @param {(number|string)} [options.w=null] The write concern.
 395 * @param {number} [options.wtimeout=null] The write concern timeout.
 396 * @param {boolean} [options.j=false] Specify a journal write concern.
 397 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
 398 * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
 399 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
 400 * @param {ClientSession} [options.session] optional session to use for this operation
 401 * @param {Collection~insertOneWriteOpCallback} [callback] The command result callback
 402 * @return {Promise} returns Promise if no callback passed
 403 */
 404Collection.prototype.insertOne = function(doc, options, callback) {
 405  if (typeof options === 'function') (callback = options), (options = {});
 406  options = options || {};
 407
 408  // Add ignoreUndfined
 409  if (this.s.options.ignoreUndefined) {
 410    options = shallowClone(options);
 411    options.ignoreUndefined = this.s.options.ignoreUndefined;
 412  }
 413
 414  return executeOperation(this.s.topology, insertOne, [this, doc, options, callback]);
 415};
 416
 417var insertOne = function(self, doc, options, callback) {
 418  if (Array.isArray(doc)) {
 419    return callback(
 420      MongoError.create({ message: 'doc parameter must be an object', driver: true })
 421    );
 422  }
 423
 424  insertDocuments(self, [doc], options, function(err, r) {
 425    if (callback == null) return;
 426    if (err && callback) return callback(err);
 427    // Workaround for pre 2.6 servers
 428    if (r == null) return callback(null, { result: { ok: 1 } });
 429    // Add values to top level to ensure crud spec compatibility
 430    r.insertedCount = r.result.n;
 431    r.insertedId = doc._id;
 432    if (callback) callback(null, r);
 433  });
 434};
 435
 436var mapInserManyResults = function(docs, r) {
 437  var finalResult = {
 438    result: { ok: 1, n: r.insertedCount },
 439    ops: docs,
 440    insertedCount: r.insertedCount,
 441    insertedIds: r.insertedIds
 442  };
 443
 444  if (r.getLastOp()) {
 445    finalResult.result.opTime = r.getLastOp();
 446  }
 447
 448  return finalResult;
 449};
 450
 451define.classMethod('insertOne', { callback: true, promise: true });
 452
 453/**
 454 * Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
 455 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
 456 * can be overridden by setting the **forceServerObjectId** flag.
 457 *
 458 * @method
 459 * @param {object[]} docs Documents to insert.
 460 * @param {object} [options=null] Optional settings.
 461 * @param {(number|string)} [options.w=null] The write concern.
 462 * @param {number} [options.wtimeout=null] The write concern timeout.
 463 * @param {boolean} [options.j=false] Specify a journal write concern.
 464 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
 465 * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
 466 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
 467 * @param {boolean} [options.ordered=true] If true, when an insert fails, don't execute the remaining writes. If false, continue with remaining inserts when one fails.
 468 * @param {ClientSession} [options.session] optional session to use for this operation
 469 * @param {Collection~insertWriteOpCallback} [callback] The command result callback
 470 * @return {Promise} returns Promise if no callback passed
 471 */
 472Collection.prototype.insertMany = function(docs, options, callback) {
 473  var self = this;
 474  if (typeof options === 'function') (callback = options), (options = {});
 475  options = options ? shallowClone(options) : { ordered: true };
 476  if (!Array.isArray(docs) && typeof callback === 'function') {
 477    return callback(
 478      MongoError.create({ message: 'docs parameter must be an array of documents', driver: true })
 479    );
 480  } else if (!Array.isArray(docs)) {
 481    return new this.s.promiseLibrary(function(resolve, reject) {
 482      reject(
 483        MongoError.create({ message: 'docs parameter must be an array of documents', driver: true })
 484      );
 485    });
 486  }
 487
 488  // If keep going set unordered
 489  options['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
 490
 491  // Set up the force server object id
 492  var forceServerObjectId =
 493    typeof options.forceServerObjectId === 'boolean'
 494      ? options.forceServerObjectId
 495      : self.s.db.options.forceServerObjectId;
 496
 497  // Do we want to force the server to assign the _id key
 498  if (forceServerObjectId !== true) {
 499    // Add _id if not specified
 500    for (var i = 0; i < docs.length; i++) {
 501      if (docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
 502    }
 503  }
 504
 505  // Generate the bulk write operations
 506  var operations = [
 507    {
 508      insertMany: docs
 509    }
 510  ];
 511
 512  return executeOperation(this.s.topology, bulkWrite, [this, operations, options, callback], {
 513    resultMutator: result => mapInserManyResults(docs, result)
 514  });
 515};
 516
 517define.classMethod('insertMany', { callback: true, promise: true });
 518
 519/**
 520 * @typedef {Object} Collection~BulkWriteOpResult
 521 * @property {number} insertedCount Number of documents inserted.
 522 * @property {number} matchedCount Number of documents matched for update.
 523 * @property {number} modifiedCount Number of documents modified.
 524 * @property {number} deletedCount Number of documents deleted.
 525 * @property {number} upsertedCount Number of documents upserted.
 526 * @property {object} insertedIds Inserted document generated Id's, hash key is the index of the originating operation
 527 * @property {object} upsertedIds Upserted document generated Id's, hash key is the index of the originating operation
 528 * @property {object} result The command result object.
 529 */
 530
 531/**
 532 * The callback format for inserts
 533 * @callback Collection~bulkWriteOpCallback
 534 * @param {BulkWriteError} error An error instance representing the error during the execution.
 535 * @param {Collection~BulkWriteOpResult} result The result object if the command was executed successfully.
 536 */
 537
 538/**
 539 * Perform a bulkWrite operation without a fluent API
 540 *
 541 * Legal operation types are
 542 *
 543 *  { insertOne: { document: { a: 1 } } }
 544 *
 545 *  { updateOne: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
 546 *
 547 *  { updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
 548 *
 549 *  { deleteOne: { filter: {c:1} } }
 550 *
 551 *  { deleteMany: { filter: {c:1} } }
 552 *
 553 *  { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}
 554 *
 555 * If documents passed in do not contain the **_id** field,
 556 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
 557 * can be overridden by setting the **forceServerObjectId** flag.
 558 *
 559 * @method
 560 * @param {object[]} operations Bulk operations to perform.
 561 * @param {object} [options=null] Optional settings.
 562 * @param {(number|string)} [options.w=null] The write concern.
 563 * @param {number} [options.wtimeout=null] The write concern timeout.
 564 * @param {boolean} [options.j=false] Specify a journal write concern.
 565 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
 566 * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
 567 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
 568 * @param {ClientSession} [options.session] optional session to use for this operation
 569 * @param {Collection~bulkWriteOpCallback} [callback] The command result callback
 570 * @return {Promise} returns Promise if no callback passed
 571 */
 572Collection.prototype.bulkWrite = function(operations, options, callback) {
 573  if (typeof options === 'function') (callback = options), (options = {});
 574  options = options || { ordered: true };
 575
 576  if (!Array.isArray(operations)) {
 577    throw MongoError.create({ message: 'operations must be an array of documents', driver: true });
 578  }
 579
 580  return executeOperation(this.s.topology, bulkWrite, [this, operations, options, callback]);
 581};
 582
 583var bulkWrite = function(self, operations, options, callback) {
 584  // Add ignoreUndfined
 585  if (self.s.options.ignoreUndefined) {
 586    options = shallowClone(options);
 587    options.ignoreUndefined = self.s.options.ignoreUndefined;
 588  }
 589
 590  // Create the bulk operation
 591  var bulk =
 592    options.ordered === true || options.ordered == null
 593      ? self.initializeOrderedBulkOp(options)
 594      : self.initializeUnorderedBulkOp(options);
 595
 596  // Do we have a collation
 597  var collation = false;
 598
 599  // for each op go through and add to the bulk
 600  try {
 601    for (var i = 0; i < operations.length; i++) {
 602      // Get the operation type
 603      var key = Object.keys(operations[i])[0];
 604      // Check if we have a collation
 605      if (operations[i][key].collation) {
 606        collation = true;
 607      }
 608
 609      // Pass to the raw bulk
 610      bulk.raw(operations[i]);
 611    }
 612  } catch (err) {
 613    return callback(err, null);
 614  }
 615
 616  // Final options for write concern
 617  var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
 618  var writeCon = finalOptions.writeConcern ? finalOptions.writeConcern : {};
 619  var capabilities = self.s.topology.capabilities();
 620
 621  // Did the user pass in a collation, check if our write server supports it
 622  if (collation && capabilities && !capabilities.commandsTakeCollation) {
 623    return callback(new MongoError(f('server/primary/mongos does not support collation')));
 624  }
 625
 626  // Execute the bulk
 627  bulk.execute(writeCon, finalOptions, function(err, r) {
 628    // We have connection level error
 629    if (!r && err) {
 630      return callback(err, null);
 631    }
 632
 633    r.insertedCount = r.nInserted;
 634    r.matchedCount = r.nMatched;
 635    r.modifiedCount = r.nModified || 0;
 636    r.deletedCount = r.nRemoved;
 637    r.upsertedCount = r.getUpsertedIds().length;
 638    r.upsertedIds = {};
 639    r.insertedIds = {};
 640
 641    // Update the n
 642    r.n = r.insertedCount;
 643
 644    // Inserted documents
 645    var inserted = r.getInsertedIds();
 646    // Map inserted ids
 647    for (var i = 0; i < inserted.length; i++) {
 648      r.insertedIds[inserted[i].index] = inserted[i]._id;
 649    }
 650
 651    // Upserted documents
 652    var upserted = r.getUpsertedIds();
 653    // Map upserted ids
 654    for (i = 0; i < upserted.length; i++) {
 655      r.upsertedIds[upserted[i].index] = upserted[i]._id;
 656    }
 657
 658    // Return the results
 659    callback(null, r);
 660  });
 661};
 662
 663var insertDocuments = function(self, docs, options, callback) {
 664  if (typeof options === 'function') (callback = options), (options = {});
 665  options = options || {};
 666  // Ensure we are operating on an array op docs
 667  docs = Array.isArray(docs) ? docs : [docs];
 668
 669  // Get the write concern options
 670  var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
 671
 672  // If keep going set unordered
 673  if (finalOptions.keepGoing === true) finalOptions.ordered = false;
 674  finalOptions['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
 675
 676  // Set up the force server object id
 677  var forceServerObjectId =
 678    typeof options.forceServerObjectId === 'boolean'
 679      ? options.forceServerObjectId
 680      : self.s.db.options.forceServerObjectId;
 681
 682  // Add _id if not specified
 683  if (forceServerObjectId !== true) {
 684    for (var i = 0; i < docs.length; i++) {
 685      if (docs[i]._id === void 0) docs[i]._id = self.s.pkFactory.createPk();
 686    }
 687  }
 688
 689  // File inserts
 690  self.s.topology.insert(self.s.namespace, docs, finalOptions, function(err, result) {
 691    if (callback == null) return;
 692    if (err) return handleCallback(callback, err);
 693    if (result == null) return handleCallback(callback, null, null);
 694    if (result.result.code) return handleCallback(callback, toError(result.result));
 695    if (result.result.writeErrors)
 696      return handleCallback(callback, toError(result.result.writeErrors[0]));
 697    // Add docs to the list
 698    result.ops = docs;
 699    // Return the results
 700    handleCallback(callback, null, result);
 701  });
 702};
 703
 704define.classMethod('bulkWrite', { callback: true, promise: true });
 705
 706/**
 707 * @typedef {Object} Collection~WriteOpResult
 708 * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
 709 * @property {object} connection The connection object used for the operation.
 710 * @property {object} result The command result object.
 711 */
 712
 713/**
 714 * The callback format for inserts
 715 * @callback Collection~writeOpCallback
 716 * @param {MongoError} error An error instance representing the error during the execution.
 717 * @param {Collection~WriteOpResult} result The result object if the command was executed successfully.
 718 */
 719
 720/**
 721 * @typedef {Object} Collection~insertWriteOpResult
 722 * @property {Number} insertedCount The total amount of documents inserted.
 723 * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
 724 * @property {Object.<Number, ObjectId>} insertedIds Map of the index of the inserted document to the id of the inserted document.
 725 * @property {object} connection The connection object used for the operation.
 726 * @property {object} result The raw command result object returned from MongoDB (content might vary by server version).
 727 * @property {Number} result.ok Is 1 if the command executed correctly.
 728 * @property {Number} result.n The total count of documents inserted.
 729 */
 730
 731/**
 732 * @typedef {Object} Collection~insertOneWriteOpResult
 733 * @property {Number} insertedCount The total amount of documents inserted.
 734 * @property {object[]} ops All the documents inserted using insertOne/insertMany/replaceOne. Documents contain the _id field if forceServerObjectId == false for insertOne/insertMany
 735 * @property {ObjectId} insertedId The driver generated ObjectId for the insert operation.
 736 * @property {object} connection The connection object used for the operation.
 737 * @property {object} result The raw command result object returned from MongoDB (content might vary by server version).
 738 * @property {Number} result.ok Is 1 if the command executed correctly.
 739 * @property {Number} result.n The total count of documents inserted.
 740 */
 741
 742/**
 743 * The callback format for inserts
 744 * @callback Collection~insertWriteOpCallback
 745 * @param {MongoError} error An error instance representing the error during the execution.
 746 * @param {Collection~insertWriteOpResult} result The result object if the command was executed successfully.
 747 */
 748
 749/**
 750 * The callback format for inserts
 751 * @callback Collection~insertOneWriteOpCallback
 752 * @param {MongoError} error An error instance representing the error during the execution.
 753 * @param {Collection~insertOneWriteOpResult} result The result object if the command was executed successfully.
 754 */
 755
 756/**
 757 * Inserts a single document or a an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
 758 * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
 759 * can be overridden by setting the **forceServerObjectId** flag.
 760 *
 761 * @method
 762 * @param {(object|object[])} docs Documents to insert.
 763 * @param {object} [options=null] Optional settings.
 764 * @param {(number|string)} [options.w=null] The write concern.
 765 * @param {number} [options.wtimeout=null] The write concern timeout.
 766 * @param {boolean} [options.j=false] Specify a journal write concern.
 767 * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
 768 * @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
 769 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
 770 * @param {ClientSession} [options.session] optional session to use for this operation
 771 * @param {Collection~insertWriteOpCallback} [callback] The command result callback
 772 * @return {Promise} returns Promise if no callback passed
 773 * @deprecated Use insertOne, insertMany or bulkWrite
 774 */
 775Collection.prototype.insert = function(docs, options, callback) {
 776  if (typeof options === 'function') (callback = options), (options = {});
 777  options = options || { ordered: false };
 778  docs = !Array.isArray(docs) ? [docs] : docs;
 779
 780  if (options.keepGoing === true) {
 781    options.ordered = false;
 782  }
 783
 784  return this.insertMany(docs, options, callback);
 785};
 786
 787define.classMethod('insert', { callback: true, promise: true });
 788
 789/**
 790 * @typedef {Object} Collection~updateWriteOpResult
 791 * @property {Object} result The raw result returned from MongoDB, field will vary depending on server version.
 792 * @property {Number} result.ok Is 1 if the command executed correctly.
 793 * @property {Number} result.n The total count of documents scanned.
 794 * @property {Number} result.nModified The total count of documents modified.
 795 * @property {Object} connection The connection object used for the operation.
 796 * @property {Number} matchedCount The number of documents that matched the filter.
 797 * @property {Number} modifiedCount The number of documents that were modified.
 798 * @property {Number} upsertedCount The number of documents upserted.
 799 * @property {Object} upsertedId The upserted id.
 800 * @property {ObjectId} upsertedId._id The upserted _id returned from the server.
 801 */
 802
 803/**
 804 * The callback format for inserts
 805 * @callback Collection~updateWriteOpCallback
 806 * @param {MongoError} error An error instance representing the error during the execution.
 807 * @param {Collection~updateWriteOpResult} result The result object if the command was executed successfully.
 808 */
 809
 810/**
 811 * Update a single document on MongoDB
 812 * @method
 813 * @param {object} filter The Filter used to select the document to update
 814 * @param {object} update The update operations to be applied to the document
 815 * @param {object} [options=null] Optional settings.
 816 * @param {boolean} [options.upsert=false] Update operation is an upsert.
 817 * @param {(number|string)} [options.w=null] The write concern.
 818 * @param {number} [options.wtimeout=null] The write concern timeout.
 819 * @param {boolean} [options.j=false] Specify a journal write concern.
 820 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
 821 * @param {Array} [options.arrayFilters=null] optional list of array filters referenced in filtered positional operators
 822 * @param {ClientSession} [options.session] optional session to use for this operation
 823 * @param {Collection~updateWriteOpCallback} [callback] The command result callback
 824 * @return {Promise} returns Promise if no callback passed
 825 */
 826Collection.prototype.updateOne = function(filter, update, options, callback) {
 827  if (typeof options === 'function') (callback = options), (options = {});
 828  options = options || {};
 829
 830  var err = checkForAtomicOperators(update);
 831  if (err) {
 832    if (typeof callback === 'function') return callback(err);
 833    return this.s.promiseLibrary.reject(err);
 834  }
 835
 836  options = shallowClone(options);
 837
 838  // Add ignoreUndfined
 839  if (this.s.options.ignoreUndefined) {
 840    options = shallowClone(options);
 841    options.ignoreUndefined = this.s.options.ignoreUndefined;
 842  }
 843
 844  return executeOperation(this.s.topology, updateOne, [this, filter, update, options, callback]);
 845};
 846
 847var checkForAtomicOperators = function(update) {
 848  var keys = Object.keys(update);
 849
 850  // same errors as the server would give for update doc lacking atomic operators
 851  if (keys.length === 0) {
 852    return toError('The update operation document must contain at least one atomic operator.');
 853  }
 854
 855  if (keys[0][0] !== '$') {
 856    return toError('the update operation document must contain atomic operators.');
 857  }
 858};
 859
 860var updateOne = function(self, filter, update, options, callback) {
 861  // Set single document update
 862  options.multi = false;
 863  // Execute update
 864  updateDocuments(self, filter, update, options, function(err, r) {
 865    if (callback == null) return;
 866    if (err && callback) return callback(err);
 867    if (r == null) return callback(null, { result: { ok: 1 } });
 868    r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
 869    r.upsertedId =
 870      Array.isArray(r.result.upserted) && r.result.upserted.length > 0
 871        ? r.result.upserted[0]
 872        : null;
 873    r.upsertedCount =
 874      Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
 875    r.matchedCount =
 876      Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
 877    if (callback) callback(null, r);
 878  });
 879};
 880
 881define.classMethod('updateOne', { callback: true, promise: true });
 882
 883/**
 884 * Replace a document on MongoDB
 885 * @method
 886 * @param {object} filter The Filter used to select the document to update
 887 * @param {object} doc The Document that replaces the matching document
 888 * @param {object} [options=null] Optional settings.
 889 * @param {boolean} [options.upsert=false] Update operation is an upsert.
 890 * @param {(number|string)} [options.w=null] The write concern.
 891 * @param {number} [options.wtimeout=null] The write concern timeout.
 892 * @param {boolean} [options.j=false] Specify a journal write concern.
 893 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
 894 * @param {ClientSession} [options.session] optional session to use for this operation
 895 * @param {Collection~updateWriteOpCallback} [callback] The command result callback
 896 * @return {Promise} returns Promise if no callback passed
 897 */
 898Collection.prototype.replaceOne = function(filter, doc, options, callback) {
 899  if (typeof options === 'function') (callback = options), (options = {});
 900  options = shallowClone(options);
 901
 902  // Add ignoreUndfined
 903  if (this.s.options.ignoreUndefined) {
 904    options = shallowClone(options);
 905    options.ignoreUndefined = this.s.options.ignoreUndefined;
 906  }
 907
 908  return executeOperation(this.s.topology, replaceOne, [this, filter, doc, options, callback]);
 909};
 910
 911var replaceOne = function(self, filter, doc, options, callback) {
 912  // Set single document update
 913  options.multi = false;
 914
 915  // Execute update
 916  updateDocuments(self, filter, doc, options, function(err, r) {
 917    if (callback == null) return;
 918    if (err && callback) return callback(err);
 919    if (r == null) return callback(null, { result: { ok: 1 } });
 920
 921    r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
 922    r.upsertedId =
 923      Array.isArray(r.result.upserted) && r.result.upserted.length > 0
 924        ? r.result.upserted[0]
 925        : null;
 926    r.upsertedCount =
 927      Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
 928    r.matchedCount =
 929      Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
 930    r.ops = [doc];
 931    if (callback) callback(null, r);
 932  });
 933};
 934
 935define.classMethod('replaceOne', { callback: true, promise: true });
 936
 937/**
 938 * Update multiple documents on MongoDB
 939 * @method
 940 * @param {object} filter The Filter used to select the documents to update
 941 * @param {object} update The update operations to be applied to the document
 942 * @param {object} [options=null] Optional settings.
 943 * @param {boolean} [options.upsert=false] Update operation is an upsert.
 944 * @param {(number|string)} [options.w=null] The write concern.
 945 * @param {number} [options.wtimeout=null] The write concern timeout.
 946 * @param {boolean} [options.j=false] Specify a journal write concern.
 947 * @param {Array} [options.arrayFilters=null] optional list of array filters referenced in filtered positional operators
 948 * @param {ClientSession} [options.session] optional session to use for this operation
 949 * @param {Collection~updateWriteOpCallback} [callback] The command result callback
 950 * @return {Promise} returns Promise if no callback passed
 951 */
 952Collection.prototype.updateMany = function(filter, update, options, callback) {
 953  if (typeof options === 'function') (callback = options), (options = {});
 954  options = options || {};
 955
 956  var err = checkForAtomicOperators(update);
 957  if (err) {
 958    if (typeof callback === 'function') return callback(err);
 959    return this.s.promiseLibrary.reject(err);
 960  }
 961
 962  options = shallowClone(options);
 963
 964  // Add ignoreUndfined
 965  if (this.s.options.ignoreUndefined) {
 966    options = shallowClone(options);
 967    options.ignoreUndefined = this.s.options.ignoreUndefined;
 968  }
 969
 970  return executeOperation(this.s.topology, updateMany, [this, filter, update, options, callback]);
 971};
 972
 973var updateMany = function(self, filter, update, options, callback) {
 974  // Set single document update
 975  options.multi = true;
 976  // Execute update
 977  updateDocuments(self, filter, update, options, function(err, r) {
 978    if (callback == null) return;
 979    if (err && callback) return callback(err);
 980    if (r == null) return callback(null, { result: { ok: 1 } });
 981    r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
 982    r.upsertedId =
 983      Array.isArray(r.result.upserted) && r.result.upserted.length > 0
 984        ? r.result.upserted[0]
 985        : null;
 986    r.upsertedCount =
 987      Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
 988    r.matchedCount =
 989      Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
 990    if (callback) callback(null, r);
 991  });
 992};
 993
 994define.classMethod('updateMany', { callback: true, promise: true });
 995
 996var updateDocuments = function(self, selector, document, options, callback) {
 997  if ('function' === typeof options) (callback = options), (options = null);
 998  if (options == null) options = {};
 999  if (!('function' === typeof callback)) callback = null;
1000
1001  // If we are not providing a selector or document throw
1002  if (selector == null || typeof selector !== 'object')
1003    return callback(toError('selector must be a valid JavaScript object'));
1004  if (document == null || typeof document !== 'object')
1005    return callback(toError('document must be a valid JavaScript object'));
1006
1007  // Get the write concern options
1008  var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
1009
1010  // Do we return the actual result document
1011  // Either use override on the function, or go back to default on either the collection
1012  // level or db
1013  finalOptions['serializeFunctions'] = options['serializeFunctions'] || self.s.serializeFunctions;
1014
1015  // Execute the operation
1016  var op = { q: selector, u: document };
1017  op.upsert = options.upsert !== void 0 ? !!options.upsert : false;
1018  op.multi = options.multi !== void 0 ? !!options.multi : false;
1019
1020  if (finalOptions.arrayFilters) {
1021    op.arrayFilters = finalOptions.arrayFilters;
1022    delete finalOptions.arrayFilters;
1023  }
1024
1025  // Have we specified collation
1026  decorateWithCollation(finalOptions, self, options);
1027
1028  // Update options
1029  self.s.topology.update(self.s.namespace, [op], finalOptions, function(err, result) {
1030    if (callback == null) return;
1031    if (err) return handleCallback(callback, err, null);
1032    if (result == null) return handleCallback(callback, null, null);
1033    if (result.result.code) return handleCallback(callback, toError(result.result));
1034    if (result.result.writeErrors)
1035      return handleCallback(callback, toError(result.result.writeErrors[0]));
1036    // Return the results
1037    handleCallback(callback, null, result);
1038  });
1039};
1040
1041/**
1042 * Updates documents.
1043 * @method
1044 * @param {object} selector The selector for the update operation.
1045 * @param {object} document The update document.
1046 * @param {object} [options=null] Optional settings.
1047 * @param {(number|string)} [options.w=null] The write concern.
1048 * @param {number} [options.wtimeout=null] The write concern timeout.
1049 * @param {boolean} [options.j=false] Specify a journal write concern.
1050 * @param {boolean} [options.upsert=false] Update operation is an upsert.
1051 * @param {boolean} [options.multi=false] Update one/all documents with operation.
1052 * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
1053 * @param {object} [options.collation=null] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
1054 * @param {Array} [options.arrayFilters=null] optional list of array filters referenced in filtered positional operators
1055 * @param {ClientSession} [options.session] optional session to use for this operation
1056 * @param {Collection~writeOpCallback} [callback] The command result callback
1057 * @throws {MongoError}
1058 * @return {Promise} returns Promise if no callback passed
1059 * @deprecated use updateOne, updateMany or bulkWrite
1060 */
1061Collection.prototype.update = function(selector, document, options, callback) {
1062  if (typeof options === 'function') (callback = options), (options = {});
1063  options = options || {};
1064
1065  // Add ignoreUndfined
1066  if (this.s.options.ignoreUndefined) {
1067    options = shallowClone(options);
1068    options.ignoreUndefined = this.s.options.ignoreUndefined;
1069  }
1070
1071  return executeOperation(this.s.topology, updateDocuments, [
1072    this,
1073    selector,
1074    document,
1075    options,
1076    callback
1077  ]);
1078};
1079
1080define.classMethod('update', { callback: true, promise: true });
1081
1082/**
1083 * @typedef {Object} Collection~deleteWriteOpResult
1084 * @property {Object} result The raw result returned from MongoDB, field will vary depending on server version.
1085 * @property {Number} result.ok Is 1 if the command executed correctly.
1086 * @property {Number} result.n The total count of documents deleted.
1087 * @property {Object} connection The connection object used for the operation.
1088 * @property {Number} deletedCount The number of documents deleted.
1089 */
1090
1091/**
1092 * The callback format for inserts
1093 * @callback Collection~deleteWriteOpCallback
1094 * @param {MongoError} error An error instance representing the error during the execution.
1095 * @param {Collection~deleteWriteOpResult} result The result object if the command was executed successfully.
1096 */
1097
1098/**
1099 * Delete a document on MongoDB
1100 * @method
1101 * @param {object} filter The Filter used to select the document to remove
1102 * @param {object} [options=null] Optional settings.
1103 * @param {(number|string)} [options.w=null] The write concern.
1104 * @param {number} [options.wtimeout=null] The write concern timeout.
1105 * @param {boolean} [options.j=false] Specify a journal write concern.
1106 * @param {ClientSession} [options.session] optional session to use for this operation
1107 * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
1108 * @return {Promise} returns Promise if no callback passed
1109 */
1110Collection.prototype.deleteOne = function(filter, options, callback) {
1111  if (typeof options === 'function') (callback = options), (options = {});
1112  options = shallowClone(options);
1113
1114  // Add ignoreUndfined
1115  if (this.s.options.ignoreUndefined) {
1116    options = shallowClone(options);
1117    options.ignoreUndefined = this.s.options.ignoreUndefined;
1118  }
1119
1120  return executeOperation(this.s.topology, deleteOne, [this, filter, options, callback]);
1121};
1122
1123var deleteOne = function(self, filter, options, callback) {
1124  options.single = true;
1125  removeDocuments(self, filter, options, function(err, r) {
1126    if (callback == null) return;
1127    if (err && callback) return callback(err);
1128    if (r == null) return callback(null, { result: { ok: 1 } });
1129    r.deletedCount = r.result.n;
1130    if (callback) callback(null, r);
1131  });
1132};
1133
1134define.classMethod('deleteOne', { callback: true, promise: true });
1135
1136Collection.prototype.removeOne = Collection.prototype.deleteOne;
1137
1138define.classMethod('removeOne', { callback: true, promise: true });
1139
1140/**
1141 * Delete multiple documents on MongoDB
1142 * @method
1143 * @param {object} filter The Filter used to select the documents to remove
1144 * @param {object} [options=null] Optional settings.
1145 * @param {(number|string)} [options.w=null] The write concern.
1146 * @param {number} [options.wtimeout=null] The write concern timeout.
1147 * @param {boolean} [options.j=false] Specify a journal write concern.
1148 * @param {ClientSession} [options.session] optional session to use for this operation
1149 * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
1150 * @return {Promise} returns Promise if no callback passed
1151 */
1152Collection.prototype.deleteMany = function(filter, options, callback) {
1153  if (typeof options === 'function') (callback = options), (options = {});
1154  options = shallowClone(options);
1155
1156  // Add ignoreUndfined
1157  if (this.s.options.ignoreUndefined) {
1158    options = shallowClone(options);
1159    options.ignoreUndefined = this.s.options.ignoreUndefined;
1160  }
1161
1162  return executeOperation(this.s.topology, deleteMany, [this, filter, options, callback]);
1163};
1164
1165var deleteMany = function(self, filter, options, callback) {
1166  options.single = false;
1167
1168  removeDocuments(self, filter, options, function(err, r) {
1169    if (callback == null) return;
1170    if (err && callback) return callback(err);
1171    if (r == null) return callback(null, { result: { ok: 1 } });
1172    r.deletedCount = r.result.n;
1173    if (callback) callback(null, r);
1174  });
1175};
1176
1177var removeDocuments = function(self, selector, options, callback) {
1178  if (typeof options === 'function') {
1179    (callback = options), (options = {});
1180  } else if (typeof selector === 'function') {
1181    callback = selector;
1182    options = {};
1183    selector = {};
1184  }
1185
1186  // Create an empty options object if the provided one is null
1187  options = options || {};
1188
1189  // Get the write concern options
1190  var finalOptions = writeConcern(shallowClone(options), self.s.db, self, options);
1191
1192  // If selector is null set empty
1193  if (selector == null) selector = {};
1194
1195  // Build the op
1196  var op = { q: selector, limit: 0 };
1197  if (options.single) op.limit = 1;
1198
1199  // Have we specified collation
1200  decorateWithCollation(finalOptions, self, options);
1201
1202  // Execute the remove
1203  self.s.topology.remove(self.s.namespace, [op], finalOptions, function(err, result) {
1204    if (callback == null) return;
1205    if (err) return handleCallback(callback, err, null);
1206    if (result == null) return handleCallback(callback, null, null);
1207    if (result.result.code) return handleCallback(callback, toError(result.result));
1208    if (result.result.writeErrors)
1209      return handleCallback(callback, toError(result.result.writeErrors[0]));
1210    // Return the results
1211    handleCallback(callback, null, result);
1212  });
1213};
1214
1215define.classMethod('deleteMany', { callback: true, promise: true });
1216
1217Collection.prototype.removeMany = Collection.prototype.deleteMany;
1218
1219define.classMethod('removeMany', { callback: true, promise: true });
1220
1221/**
1222 * Remove documents.
1223 * @method
1224 * @param {object} selector The selector for the update operation.
1225 * @param {object} [options=null] Optional settings.
1226 * @param {(number|string)} [options.w=null] The write concern.
1227 * @param {number} [options.wtimeout=null] The write concern timeout.
1228 * @param {boolean} [options.j=false] Specify a journal write concern.
1229 * @param {boolean} [options.single=false] Removes the first document found.
1230 * @param {ClientSession} [options.session] optional session to use for this operation
1231 * @param {Collection~writeOpCallback} [callback] The command result callback
1232 * @return {Promise} returns Promise if no callback passed
1233 * @deprecated use deleteOne, deleteMany or bulkWrite
1234 */
1235Collection.prototype.remove = function(selector, options, callback) {
1236  if (typeof options === 'function') (callback = options), (options = {});
1237 

Large files files are truncated, but you can click here to view the full file