|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479 |
- 'use strict';
-
- const applyWriteConcern = require('../utils').applyWriteConcern;
- const applyRetryableWrites = require('../utils').applyRetryableWrites;
- const checkCollectionName = require('../utils').checkCollectionName;
- const Code = require('mongodb-core').BSON.Code;
- const createIndexDb = require('./db_ops').createIndex;
- const decorateCommand = require('../utils').decorateCommand;
- const decorateWithCollation = require('../utils').decorateWithCollation;
- const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
- const ensureIndexDb = require('./db_ops').ensureIndex;
- const evaluate = require('./db_ops').evaluate;
- const executeCommand = require('./db_ops').executeCommand;
- const executeDbAdminCommand = require('./db_ops').executeDbAdminCommand;
- const formattedOrderClause = require('../utils').formattedOrderClause;
- const resolveReadPreference = require('../utils').resolveReadPreference;
- const handleCallback = require('../utils').handleCallback;
- const indexInformationDb = require('./db_ops').indexInformation;
- const isObject = require('../utils').isObject;
- const Long = require('mongodb-core').BSON.Long;
- const MongoError = require('mongodb-core').MongoError;
- const ReadPreference = require('mongodb-core').ReadPreference;
- const toError = require('../utils').toError;
-
- /**
- * Group function helper
- * @ignore
- */
- // var groupFunction = function () {
- // var c = db[ns].find(condition);
- // var map = new Map();
- // var reduce_function = reduce;
- //
- // while (c.hasNext()) {
- // var obj = c.next();
- // var key = {};
- //
- // for (var i = 0, len = keys.length; i < len; ++i) {
- // var k = keys[i];
- // key[k] = obj[k];
- // }
- //
- // var aggObj = map.get(key);
- //
- // if (aggObj == null) {
- // var newObj = Object.extend({}, key);
- // aggObj = Object.extend(newObj, initial);
- // map.put(key, aggObj);
- // }
- //
- // reduce_function(obj, aggObj);
- // }
- //
- // return { "result": map.values() };
- // }.toString();
- const 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}';
-
- /**
- * Perform a bulkWrite operation. See Collection.prototype.bulkWrite for more information.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object[]} operations Bulk operations to perform.
- * @param {object} [options] Optional settings. See Collection.prototype.bulkWrite for a list of options.
- * @param {Collection~bulkWriteOpCallback} [callback] The command result callback
- */
- function bulkWrite(coll, operations, options, callback) {
- // Add ignoreUndfined
- if (coll.s.options.ignoreUndefined) {
- options = Object.assign({}, options);
- options.ignoreUndefined = coll.s.options.ignoreUndefined;
- }
-
- // Create the bulk operation
- const bulk =
- options.ordered === true || options.ordered == null
- ? coll.initializeOrderedBulkOp(options)
- : coll.initializeUnorderedBulkOp(options);
-
- // Do we have a collation
- let collation = false;
-
- // for each op go through and add to the bulk
- try {
- for (let i = 0; i < operations.length; i++) {
- // Get the operation type
- const key = Object.keys(operations[i])[0];
- // Check if we have a collation
- if (operations[i][key].collation) {
- collation = true;
- }
-
- // Pass to the raw bulk
- bulk.raw(operations[i]);
- }
- } catch (err) {
- return callback(err, null);
- }
-
- // Final options for retryable writes and write concern
- let finalOptions = Object.assign({}, options);
- finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
- finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
-
- const writeCon = finalOptions.writeConcern ? finalOptions.writeConcern : {};
- const capabilities = coll.s.topology.capabilities();
-
- // Did the user pass in a collation, check if our write server supports it
- if (collation && capabilities && !capabilities.commandsTakeCollation) {
- return callback(new MongoError('server/primary/mongos does not support collation'));
- }
-
- // Execute the bulk
- bulk.execute(writeCon, finalOptions, (err, r) => {
- // We have connection level error
- if (!r && err) {
- return callback(err, null);
- }
-
- r.insertedCount = r.nInserted;
- r.matchedCount = r.nMatched;
- r.modifiedCount = r.nModified || 0;
- r.deletedCount = r.nRemoved;
- r.upsertedCount = r.getUpsertedIds().length;
- r.upsertedIds = {};
- r.insertedIds = {};
-
- // Update the n
- r.n = r.insertedCount;
-
- // Inserted documents
- const inserted = r.getInsertedIds();
- // Map inserted ids
- for (let i = 0; i < inserted.length; i++) {
- r.insertedIds[inserted[i].index] = inserted[i]._id;
- }
-
- // Upserted documents
- const upserted = r.getUpsertedIds();
- // Map upserted ids
- for (let i = 0; i < upserted.length; i++) {
- r.upsertedIds[upserted[i].index] = upserted[i]._id;
- }
-
- // Return the results
- callback(null, r);
- });
- }
-
- // Check the update operation to ensure it has atomic operators.
- function checkForAtomicOperators(update) {
- const keys = Object.keys(update);
-
- // same errors as the server would give for update doc lacking atomic operators
- if (keys.length === 0) {
- return toError('The update operation document must contain at least one atomic operator.');
- }
-
- if (keys[0][0] !== '$') {
- return toError('the update operation document must contain atomic operators.');
- }
- }
-
- /**
- * Count the number of documents in the collection that match the query.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} query The query for the count.
- * @param {object} [options] Optional settings. See Collection.prototype.count for a list of options.
- * @param {Collection~countCallback} [callback] The command result callback
- */
- function count(coll, query, options, callback) {
- if (typeof options === 'function') (callback = options), (options = {});
- options = Object.assign({}, options);
- options.collectionName = coll.s.name;
-
- options.readPreference = resolveReadPreference(options, {
- db: coll.s.db,
- collection: coll
- });
-
- let cmd;
- try {
- cmd = buildCountCommand(coll, query, options);
- } catch (err) {
- return callback(err);
- }
-
- executeCommand(coll.s.db, cmd, options, (err, result) => {
- if (err) return handleCallback(callback, err);
- handleCallback(callback, null, result.n);
- });
- }
-
- function countDocuments(coll, query, options, callback) {
- const skip = options.skip;
- const limit = options.limit;
- options = Object.assign({}, options);
-
- const pipeline = [{ $match: query }];
-
- // Add skip and limit if defined
- if (typeof skip === 'number') {
- pipeline.push({ $skip: skip });
- }
-
- if (typeof limit === 'number') {
- pipeline.push({ $limit: limit });
- }
-
- pipeline.push({ $group: { _id: null, n: { $sum: 1 } } });
-
- delete options.limit;
- delete options.skip;
-
- coll.aggregate(pipeline, options).toArray((err, docs) => {
- if (err) return handleCallback(callback, err);
- handleCallback(callback, null, docs.length ? docs[0].n : 0);
- });
- }
-
- /**
- * Build the count command.
- *
- * @method
- * @param {collectionOrCursor} an instance of a collection or cursor
- * @param {object} query The query for the count.
- * @param {object} [options] Optional settings. See Collection.prototype.count and Cursor.prototype.count for a list of options.
- */
- function buildCountCommand(collectionOrCursor, query, options) {
- const skip = options.skip;
- const limit = options.limit;
- let hint = options.hint;
- const maxTimeMS = options.maxTimeMS;
- query = query || {};
-
- // Final query
- const cmd = {
- count: options.collectionName,
- query: query
- };
-
- // check if collectionOrCursor is a cursor by using cursor.s.numberOfRetries
- if (collectionOrCursor.s.numberOfRetries) {
- if (collectionOrCursor.s.options.hint) {
- hint = collectionOrCursor.s.options.hint;
- } else if (collectionOrCursor.s.cmd.hint) {
- hint = collectionOrCursor.s.cmd.hint;
- }
- decorateWithCollation(cmd, collectionOrCursor, collectionOrCursor.s.cmd);
- } else {
- decorateWithCollation(cmd, collectionOrCursor, options);
- }
-
- // Add limit, skip and maxTimeMS if defined
- if (typeof skip === 'number') cmd.skip = skip;
- if (typeof limit === 'number') cmd.limit = limit;
- if (typeof maxTimeMS === 'number') cmd.maxTimeMS = maxTimeMS;
- if (hint) cmd.hint = hint;
-
- // Do we have a readConcern specified
- decorateWithReadConcern(cmd, collectionOrCursor);
-
- return cmd;
- }
-
- /**
- * Create an index on the db and collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {(string|object)} fieldOrSpec Defines the index.
- * @param {object} [options] Optional settings. See Collection.prototype.createIndex for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function createIndex(coll, fieldOrSpec, options, callback) {
- createIndexDb(coll.s.db, coll.s.name, fieldOrSpec, options, callback);
- }
-
- /**
- * Create multiple indexes in the collection. This method is only supported for
- * MongoDB 2.6 or higher. Earlier version of MongoDB will throw a command not supported
- * error. Index specifications are defined at http://docs.mongodb.org/manual/reference/command/createIndexes/.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {array} indexSpecs An array of index specifications to be created
- * @param {Object} [options] Optional settings. See Collection.prototype.createIndexes for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function createIndexes(coll, indexSpecs, options, callback) {
- const capabilities = coll.s.topology.capabilities();
-
- // Ensure we generate the correct name if the parameter is not set
- for (let i = 0; i < indexSpecs.length; i++) {
- if (indexSpecs[i].name == null) {
- const keys = [];
-
- // Did the user pass in a collation, check if our write server supports it
- if (indexSpecs[i].collation && capabilities && !capabilities.commandsTakeCollation) {
- return callback(new MongoError('server/primary/mongos does not support collation'));
- }
-
- for (let name in indexSpecs[i].key) {
- keys.push(`${name}_${indexSpecs[i].key[name]}`);
- }
-
- // Set the name
- indexSpecs[i].name = keys.join('_');
- }
- }
-
- options = Object.assign({}, options, { readPreference: ReadPreference.PRIMARY });
-
- // Execute the index
- executeCommand(
- coll.s.db,
- {
- createIndexes: coll.s.name,
- indexes: indexSpecs
- },
- options,
- callback
- );
- }
-
- function deleteCallback(err, r, callback) {
- if (callback == null) return;
- if (err && callback) return callback(err);
- if (r == null) return callback(null, { result: { ok: 1 } });
- r.deletedCount = r.result.n;
- if (callback) callback(null, r);
- }
-
- /**
- * Delete multiple documents from the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter The Filter used to select the documents to remove
- * @param {object} [options] Optional settings. See Collection.prototype.deleteMany for a list of options.
- * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
- */
- function deleteMany(coll, filter, options, callback) {
- options.single = false;
-
- removeDocuments(coll, filter, options, (err, r) => deleteCallback(err, r, callback));
- }
-
- /**
- * Delete a single document from the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter The Filter used to select the document to remove
- * @param {object} [options] Optional settings. See Collection.prototype.deleteOne for a list of options.
- * @param {Collection~deleteWriteOpCallback} [callback] The command result callback
- */
- function deleteOne(coll, filter, options, callback) {
- options.single = true;
- removeDocuments(coll, filter, options, (err, r) => deleteCallback(err, r, callback));
- }
-
- /**
- * Return a list of distinct values for the given key across a collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {string} key Field of the document to find distinct values for.
- * @param {object} query The query for filtering the set of documents to which we apply the distinct filter.
- * @param {object} [options] Optional settings. See Collection.prototype.distinct for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function distinct(coll, key, query, options, callback) {
- // maxTimeMS option
- const maxTimeMS = options.maxTimeMS;
-
- // Distinct command
- const cmd = {
- distinct: coll.s.name,
- key: key,
- query: query
- };
-
- options = Object.assign({}, options);
- // Ensure we have the right read preference inheritance
- options.readPreference = resolveReadPreference(options, { db: coll.s.db, collection: coll });
-
- // Add maxTimeMS if defined
- if (typeof maxTimeMS === 'number') cmd.maxTimeMS = maxTimeMS;
-
- // Do we have a readConcern specified
- decorateWithReadConcern(cmd, coll, options);
-
- // Have we specified collation
- try {
- decorateWithCollation(cmd, coll, options);
- } catch (err) {
- return callback(err, null);
- }
-
- // Execute the command
- executeCommand(coll.s.db, cmd, options, (err, result) => {
- if (err) return handleCallback(callback, err);
- handleCallback(callback, null, result.values);
- });
- }
-
- /**
- * Drop an index from this collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {string} indexName Name of the index to drop.
- * @param {object} [options] Optional settings. See Collection.prototype.dropIndex for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function dropIndex(coll, indexName, options, callback) {
- // Delete index command
- const cmd = { dropIndexes: coll.s.name, index: indexName };
-
- // Decorate command with writeConcern if supported
- applyWriteConcern(cmd, { db: coll.s.db, collection: coll }, options);
-
- // Execute command
- executeCommand(coll.s.db, cmd, options, (err, result) => {
- if (typeof callback !== 'function') return;
- if (err) return handleCallback(callback, err, null);
- handleCallback(callback, null, result);
- });
- }
-
- /**
- * Drop all indexes from this collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {Object} [options] Optional settings. See Collection.prototype.dropIndexes for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function dropIndexes(coll, options, callback) {
- dropIndex(coll, '*', options, err => {
- if (err) return handleCallback(callback, err, false);
- handleCallback(callback, null, true);
- });
- }
-
- /**
- * Ensure that an index exists. If the index does not exist, this function creates it.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {(string|object)} fieldOrSpec Defines the index.
- * @param {object} [options] Optional settings. See Collection.prototype.ensureIndex for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function ensureIndex(coll, fieldOrSpec, options, callback) {
- ensureIndexDb(coll.s.db, coll.s.name, fieldOrSpec, options, callback);
- }
-
- /**
- * Find and update a document.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} query Query object to locate the object to modify.
- * @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
- * @param {object} doc The fields/vals to be updated.
- * @param {object} [options] Optional settings. See Collection.prototype.findAndModify for a list of options.
- * @param {Collection~findAndModifyCallback} [callback] The command result callback
- * @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete instead
- */
- function findAndModify(coll, query, sort, doc, options, callback) {
- // Create findAndModify command object
- const queryObject = {
- findAndModify: coll.s.name,
- query: query
- };
-
- sort = formattedOrderClause(sort);
- if (sort) {
- queryObject.sort = sort;
- }
-
- queryObject.new = options.new ? true : false;
- queryObject.remove = options.remove ? true : false;
- queryObject.upsert = options.upsert ? true : false;
-
- const projection = options.projection || options.fields;
-
- if (projection) {
- queryObject.fields = projection;
- }
-
- if (options.arrayFilters) {
- queryObject.arrayFilters = options.arrayFilters;
- delete options.arrayFilters;
- }
-
- if (doc && !options.remove) {
- queryObject.update = doc;
- }
-
- if (options.maxTimeMS) queryObject.maxTimeMS = options.maxTimeMS;
-
- // Either use override on the function, or go back to default on either the collection
- // level or db
- options.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
-
- // No check on the documents
- options.checkKeys = false;
-
- // Final options for retryable writes and write concern
- let finalOptions = Object.assign({}, options);
- finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
- finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
-
- // Decorate the findAndModify command with the write Concern
- if (finalOptions.writeConcern) {
- queryObject.writeConcern = finalOptions.writeConcern;
- }
-
- // Have we specified bypassDocumentValidation
- if (finalOptions.bypassDocumentValidation === true) {
- queryObject.bypassDocumentValidation = finalOptions.bypassDocumentValidation;
- }
-
- finalOptions.readPreference = ReadPreference.primary;
-
- // Have we specified collation
- try {
- decorateWithCollation(queryObject, coll, finalOptions);
- } catch (err) {
- return callback(err, null);
- }
-
- // Execute the command
- executeCommand(coll.s.db, queryObject, finalOptions, (err, result) => {
- if (err) return handleCallback(callback, err, null);
-
- return handleCallback(callback, null, result);
- });
- }
-
- /**
- * Find and remove a document.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} query Query object to locate the object to modify.
- * @param {array} sort If multiple docs match, choose the first one in the specified sort order as the object to manipulate.
- * @param {object} [options] Optional settings. See Collection.prototype.findAndRemove for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- * @deprecated use findOneAndDelete instead
- */
- function findAndRemove(coll, query, sort, options, callback) {
- // Add the remove option
- options.remove = true;
- // Execute the callback
- findAndModify(coll, query, sort, null, options, callback);
- }
-
- /**
- * Fetch the first document that matches the query.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} query Query for find Operation
- * @param {object} [options] Optional settings. See Collection.prototype.findOne for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function findOne(coll, query, options, callback) {
- const cursor = coll
- .find(query, options)
- .limit(-1)
- .batchSize(1);
-
- // Return the item
- cursor.next((err, item) => {
- if (err != null) return handleCallback(callback, toError(err), null);
- handleCallback(callback, null, item);
- });
- }
-
- /**
- * Find a document and delete it in one atomic operation. This requires a write lock for the duration of the operation.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter Document selection filter.
- * @param {object} [options] Optional settings. See Collection.prototype.findOneAndDelete for a list of options.
- * @param {Collection~findAndModifyCallback} [callback] The collection result callback
- */
- function findOneAndDelete(coll, filter, options, callback) {
- // Final options
- const finalOptions = Object.assign({}, options);
- finalOptions.fields = options.projection;
- finalOptions.remove = true;
- // Execute find and Modify
- findAndModify(coll, filter, options.sort, null, finalOptions, callback);
- }
-
- /**
- * Find a document and replace it in one atomic operation. This requires a write lock for the duration of the operation.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter Document selection filter.
- * @param {object} replacement Document replacing the matching document.
- * @param {object} [options] Optional settings. See Collection.prototype.findOneAndReplace for a list of options.
- * @param {Collection~findAndModifyCallback} [callback] The collection result callback
- */
- function findOneAndReplace(coll, filter, replacement, options, callback) {
- // Final options
- const finalOptions = Object.assign({}, options);
- finalOptions.fields = options.projection;
- finalOptions.update = true;
- finalOptions.new = options.returnOriginal !== void 0 ? !options.returnOriginal : false;
- finalOptions.upsert = options.upsert !== void 0 ? !!options.upsert : false;
-
- // Execute findAndModify
- findAndModify(coll, filter, options.sort, replacement, finalOptions, callback);
- }
-
- /**
- * Find a document and update it in one atomic operation. This requires a write lock for the duration of the operation.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter Document selection filter.
- * @param {object} update Update operations to be performed on the document
- * @param {object} [options] Optional settings. See Collection.prototype.findOneAndUpdate for a list of options.
- * @param {Collection~findAndModifyCallback} [callback] The collection result callback
- */
- function findOneAndUpdate(coll, filter, update, options, callback) {
- // Final options
- const finalOptions = Object.assign({}, options);
- finalOptions.fields = options.projection;
- finalOptions.update = true;
- finalOptions.new = typeof options.returnOriginal === 'boolean' ? !options.returnOriginal : false;
- finalOptions.upsert = typeof options.upsert === 'boolean' ? options.upsert : false;
-
- // Execute findAndModify
- findAndModify(coll, filter, options.sort, update, finalOptions, callback);
- }
-
- /**
- * Execute a geo search using a geo haystack index on a collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {number} x Point to search on the x axis, ensure the indexes are ordered in the same order.
- * @param {number} y Point to search on the y axis, ensure the indexes are ordered in the same order.
- * @param {object} [options] Optional settings. See Collection.prototype.geoHaystackSearch for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function geoHaystackSearch(coll, x, y, options, callback) {
- // Build command object
- let commandObject = {
- geoSearch: coll.s.name,
- near: [x, y]
- };
-
- // Remove read preference from hash if it exists
- commandObject = decorateCommand(commandObject, options, ['readPreference', 'session']);
-
- options = Object.assign({}, options);
- // Ensure we have the right read preference inheritance
- options.readPreference = resolveReadPreference(options, { db: coll.s.db, collection: coll });
-
- // Do we have a readConcern specified
- decorateWithReadConcern(commandObject, coll, options);
-
- // Execute the command
- executeCommand(coll.s.db, commandObject, options, (err, res) => {
- if (err) return handleCallback(callback, err);
- if (res.err || res.errmsg) handleCallback(callback, toError(res));
- // should we only be returning res.results here? Not sure if the user
- // should see the other return information
- handleCallback(callback, null, res);
- });
- }
-
- /**
- * Run a group command across a collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {(object|array|function|code)} keys An object, array or function expressing the keys to group by.
- * @param {object} condition An optional condition that must be true for a row to be considered.
- * @param {object} initial Initial value of the aggregation counter object.
- * @param {(function|Code)} reduce The reduce function aggregates (reduces) the objects iterated
- * @param {(function|Code)} finalize An optional function to be run on each item in the result set just before the item is returned.
- * @param {boolean} command Specify if you wish to run using the internal group command or using eval, default is true.
- * @param {object} [options] Optional settings. See Collection.prototype.group for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- * @deprecated MongoDB 3.6 or higher will no longer support the group command. We recommend rewriting using the aggregation framework.
- */
- function group(coll, keys, condition, initial, reduce, finalize, command, options, callback) {
- // Execute using the command
- if (command) {
- const reduceFunction = reduce && reduce._bsontype === 'Code' ? reduce : new Code(reduce);
-
- const selector = {
- group: {
- ns: coll.s.name,
- $reduce: reduceFunction,
- cond: condition,
- initial: initial,
- out: 'inline'
- }
- };
-
- // if finalize is defined
- if (finalize != null) selector.group['finalize'] = finalize;
- // Set up group selector
- if ('function' === typeof keys || (keys && keys._bsontype === 'Code')) {
- selector.group.$keyf = keys && keys._bsontype === 'Code' ? keys : new Code(keys);
- } else {
- const hash = {};
- keys.forEach(key => {
- hash[key] = 1;
- });
- selector.group.key = hash;
- }
-
- options = Object.assign({}, options);
- // Ensure we have the right read preference inheritance
- options.readPreference = resolveReadPreference(options, { db: coll.s.db, collection: coll });
-
- // Do we have a readConcern specified
- decorateWithReadConcern(selector, coll, options);
-
- // Have we specified collation
- try {
- decorateWithCollation(selector, coll, options);
- } catch (err) {
- return callback(err, null);
- }
-
- // Execute command
- executeCommand(coll.s.db, selector, options, (err, result) => {
- if (err) return handleCallback(callback, err, null);
- handleCallback(callback, null, result.retval);
- });
- } else {
- // Create execution scope
- const scope = reduce != null && reduce._bsontype === 'Code' ? reduce.scope : {};
-
- scope.ns = coll.s.name;
- scope.keys = keys;
- scope.condition = condition;
- scope.initial = initial;
-
- // Pass in the function text to execute within mongodb.
- const groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';');
-
- evaluate(coll.s.db, new Code(groupfn, scope), null, options, (err, results) => {
- if (err) return handleCallback(callback, err, null);
- handleCallback(callback, null, results.result || results);
- });
- }
- }
-
- /**
- * Retrieve all the indexes on the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {Object} [options] Optional settings. See Collection.prototype.indexes for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function indexes(coll, options, callback) {
- options = Object.assign({}, { full: true }, options);
- indexInformationDb(coll.s.db, coll.s.name, options, callback);
- }
-
- /**
- * Check if one or more indexes exist on the collection. This fails on the first index that doesn't exist.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {(string|array)} indexes One or more index names to check.
- * @param {Object} [options] Optional settings. See Collection.prototype.indexExists for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function indexExists(coll, indexes, options, callback) {
- indexInformation(coll, options, (err, indexInformation) => {
- // If we have an error return
- if (err != null) return handleCallback(callback, err, null);
- // Let's check for the index names
- if (!Array.isArray(indexes))
- return handleCallback(callback, null, indexInformation[indexes] != null);
- // Check in list of indexes
- for (let i = 0; i < indexes.length; i++) {
- if (indexInformation[indexes[i]] == null) {
- return handleCallback(callback, null, false);
- }
- }
-
- // All keys found return true
- return handleCallback(callback, null, true);
- });
- }
-
- /**
- * Retrieve this collection's index info.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} [options] Optional settings. See Collection.prototype.indexInformation for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function indexInformation(coll, options, callback) {
- indexInformationDb(coll.s.db, coll.s.name, options, callback);
- }
-
- function insertDocuments(coll, docs, options, callback) {
- if (typeof options === 'function') (callback = options), (options = {});
- options = options || {};
- // Ensure we are operating on an array op docs
- docs = Array.isArray(docs) ? docs : [docs];
-
- // Final options for retryable writes and write concern
- let finalOptions = Object.assign({}, options);
- finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
- finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
-
- // If keep going set unordered
- if (finalOptions.keepGoing === true) finalOptions.ordered = false;
- finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
-
- docs = prepareDocs(coll, docs, options);
-
- // File inserts
- coll.s.topology.insert(coll.s.namespace, docs, finalOptions, (err, result) => {
- if (callback == null) return;
- if (err) return handleCallback(callback, err);
- if (result == null) return handleCallback(callback, null, null);
- if (result.result.code) return handleCallback(callback, toError(result.result));
- if (result.result.writeErrors)
- return handleCallback(callback, toError(result.result.writeErrors[0]));
- // Add docs to the list
- result.ops = docs;
- // Return the results
- handleCallback(callback, null, result);
- });
- }
-
- /**
- * Insert a single document into the collection. See Collection.prototype.insertOne for more information.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} doc Document to insert.
- * @param {object} [options] Optional settings. See Collection.prototype.insertOne for a list of options.
- * @param {Collection~insertOneWriteOpCallback} [callback] The command result callback
- */
- function insertOne(coll, doc, options, callback) {
- if (Array.isArray(doc)) {
- return callback(
- MongoError.create({ message: 'doc parameter must be an object', driver: true })
- );
- }
-
- insertDocuments(coll, [doc], options, (err, r) => {
- if (callback == null) return;
- if (err && callback) return callback(err);
- // Workaround for pre 2.6 servers
- if (r == null) return callback(null, { result: { ok: 1 } });
- // Add values to top level to ensure crud spec compatibility
- r.insertedCount = r.result.n;
- r.insertedId = doc._id;
- if (callback) callback(null, r);
- });
- }
-
- /**
- * Determine whether the collection is a capped collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {Object} [options] Optional settings. See Collection.prototype.isCapped for a list of options.
- * @param {Collection~resultCallback} [callback] The results callback
- */
- function isCapped(coll, options, callback) {
- optionsOp(coll, options, (err, document) => {
- if (err) return handleCallback(callback, err);
- handleCallback(callback, null, !!(document && document.capped));
- });
- }
-
- /**
- * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {(function|string)} map The mapping function.
- * @param {(function|string)} reduce The reduce function.
- * @param {object} [options] Optional settings. See Collection.prototype.mapReduce for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function mapReduce(coll, map, reduce, options, callback) {
- const mapCommandHash = {
- mapreduce: coll.s.name,
- map: map,
- reduce: reduce
- };
-
- // Exclusion list
- const exclusionList = ['readPreference', 'session', 'bypassDocumentValidation'];
-
- // Add any other options passed in
- for (let n in options) {
- if ('scope' === n) {
- mapCommandHash[n] = processScope(options[n]);
- } else {
- // Only include if not in exclusion list
- if (exclusionList.indexOf(n) === -1) {
- mapCommandHash[n] = options[n];
- }
- }
- }
-
- options = Object.assign({}, options);
-
- // Ensure we have the right read preference inheritance
- options.readPreference = resolveReadPreference(options, { db: coll.s.db, collection: coll });
-
- // If we have a read preference and inline is not set as output fail hard
- if (
- options.readPreference !== false &&
- options.readPreference !== 'primary' &&
- options['out'] &&
- (options['out'].inline !== 1 && options['out'] !== 'inline')
- ) {
- // Force readPreference to primary
- options.readPreference = 'primary';
- // Decorate command with writeConcern if supported
- applyWriteConcern(mapCommandHash, { db: coll.s.db, collection: coll }, options);
- } else {
- decorateWithReadConcern(mapCommandHash, coll, options);
- }
-
- // Is bypassDocumentValidation specified
- if (options.bypassDocumentValidation === true) {
- mapCommandHash.bypassDocumentValidation = options.bypassDocumentValidation;
- }
-
- // Have we specified collation
- try {
- decorateWithCollation(mapCommandHash, coll, options);
- } catch (err) {
- return callback(err, null);
- }
-
- // Execute command
- executeCommand(coll.s.db, mapCommandHash, options, (err, result) => {
- if (err) return handleCallback(callback, err);
- // Check if we have an error
- if (1 !== result.ok || result.err || result.errmsg) {
- return handleCallback(callback, toError(result));
- }
-
- // Create statistics value
- const stats = {};
- if (result.timeMillis) stats['processtime'] = result.timeMillis;
- if (result.counts) stats['counts'] = result.counts;
- if (result.timing) stats['timing'] = result.timing;
-
- // invoked with inline?
- if (result.results) {
- // If we wish for no verbosity
- if (options['verbose'] == null || !options['verbose']) {
- return handleCallback(callback, null, result.results);
- }
-
- return handleCallback(callback, null, { results: result.results, stats: stats });
- }
-
- // The returned collection
- let collection = null;
-
- // If we have an object it's a different db
- if (result.result != null && typeof result.result === 'object') {
- const doc = result.result;
- // Return a collection from another db
- const Db = require('../db');
- collection = new Db(doc.db, coll.s.db.s.topology, coll.s.db.s.options).collection(
- doc.collection
- );
- } else {
- // Create a collection object that wraps the result collection
- collection = coll.s.db.collection(result.result);
- }
-
- // If we wish for no verbosity
- if (options['verbose'] == null || !options['verbose']) {
- return handleCallback(callback, err, collection);
- }
-
- // Return stats as third set of values
- handleCallback(callback, err, { collection: collection, stats: stats });
- });
- }
-
- /**
- * Return the options of the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {Object} [options] Optional settings. See Collection.prototype.options for a list of options.
- * @param {Collection~resultCallback} [callback] The results callback
- */
- function optionsOp(coll, opts, callback) {
- coll.s.db.listCollections({ name: coll.s.name }, opts).toArray((err, collections) => {
- if (err) return handleCallback(callback, err);
- if (collections.length === 0) {
- return handleCallback(
- callback,
- MongoError.create({ message: `collection ${coll.s.namespace} not found`, driver: true })
- );
- }
-
- handleCallback(callback, err, collections[0].options || null);
- });
- }
-
- /**
- * Return N parallel cursors for a collection to allow parallel reading of the entire collection. There are
- * no ordering guarantees for returned results.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} [options] Optional settings. See Collection.prototype.parallelCollectionScan for a list of options.
- * @param {Collection~parallelCollectionScanCallback} [callback] The command result callback
- */
- function parallelCollectionScan(coll, options, callback) {
- // Create command object
- const commandObject = {
- parallelCollectionScan: coll.s.name,
- numCursors: options.numCursors
- };
-
- // Do we have a readConcern specified
- decorateWithReadConcern(commandObject, coll, options);
-
- // Store the raw value
- const raw = options.raw;
- delete options['raw'];
-
- // Execute the command
- executeCommand(coll.s.db, commandObject, options, (err, result) => {
- if (err) return handleCallback(callback, err, null);
- if (result == null)
- return handleCallback(
- callback,
- new Error('no result returned for parallelCollectionScan'),
- null
- );
-
- options = Object.assign({ explicitlyIgnoreSession: true }, options);
-
- const cursors = [];
- // Add the raw back to the option
- if (raw) options.raw = raw;
- // Create command cursors for each item
- for (let i = 0; i < result.cursors.length; i++) {
- const rawId = result.cursors[i].cursor.id;
- // Convert cursorId to Long if needed
- const cursorId = typeof rawId === 'number' ? Long.fromNumber(rawId) : rawId;
- // Add a command cursor
- cursors.push(coll.s.topology.cursor(coll.s.namespace, cursorId, options));
- }
-
- handleCallback(callback, null, cursors);
- });
- }
-
- // modifies documents before being inserted or updated
- function prepareDocs(coll, docs, options) {
- const forceServerObjectId =
- typeof options.forceServerObjectId === 'boolean'
- ? options.forceServerObjectId
- : coll.s.db.options.forceServerObjectId;
-
- // no need to modify the docs if server sets the ObjectId
- if (forceServerObjectId === true) {
- return docs;
- }
-
- return docs.map(doc => {
- if (forceServerObjectId !== true && doc._id == null) {
- doc._id = coll.s.pkFactory.createPk();
- }
-
- return doc;
- });
- }
-
- /**
- * Functions that are passed as scope args must
- * be converted to Code instances.
- * @ignore
- */
- function processScope(scope) {
- if (!isObject(scope) || scope._bsontype === 'ObjectID') {
- return scope;
- }
-
- const keys = Object.keys(scope);
- let key;
- const new_scope = {};
-
- for (let i = keys.length - 1; i >= 0; i--) {
- key = keys[i];
- if ('function' === typeof scope[key]) {
- new_scope[key] = new Code(String(scope[key]));
- } else {
- new_scope[key] = processScope(scope[key]);
- }
- }
-
- return new_scope;
- }
-
- /**
- * Reindex all indexes on the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {Object} [options] Optional settings. See Collection.prototype.reIndex for a list of options.
- * @param {Collection~resultCallback} [callback] The command result callback
- */
- function reIndex(coll, options, callback) {
- // Reindex
- const cmd = { reIndex: coll.s.name };
-
- // Execute the command
- executeCommand(coll.s.db, cmd, options, (err, result) => {
- if (callback == null) return;
- if (err) return handleCallback(callback, err, null);
- handleCallback(callback, null, result.ok ? true : false);
- });
- }
-
- function removeDocuments(coll, selector, options, callback) {
- if (typeof options === 'function') {
- (callback = options), (options = {});
- } else if (typeof selector === 'function') {
- callback = selector;
- options = {};
- selector = {};
- }
-
- // Create an empty options object if the provided one is null
- options = options || {};
-
- // Final options for retryable writes and write concern
- let finalOptions = Object.assign({}, options);
- finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
- finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
-
- // If selector is null set empty
- if (selector == null) selector = {};
-
- // Build the op
- const op = { q: selector, limit: 0 };
- if (options.single) {
- op.limit = 1;
- } else if (finalOptions.retryWrites) {
- finalOptions.retryWrites = false;
- }
-
- // Have we specified collation
- try {
- decorateWithCollation(finalOptions, coll, options);
- } catch (err) {
- return callback(err, null);
- }
-
- // Execute the remove
- coll.s.topology.remove(coll.s.namespace, [op], finalOptions, (err, result) => {
- if (callback == null) return;
- if (err) return handleCallback(callback, err, null);
- if (result == null) return handleCallback(callback, null, null);
- if (result.result.code) return handleCallback(callback, toError(result.result));
- if (result.result.writeErrors)
- return handleCallback(callback, toError(result.result.writeErrors[0]));
- // Return the results
- handleCallback(callback, null, result);
- });
- }
-
- /**
- * Rename the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {string} newName New name of of the collection.
- * @param {object} [options] Optional settings. See Collection.prototype.rename for a list of options.
- * @param {Collection~collectionResultCallback} [callback] The results callback
- */
- function rename(coll, newName, options, callback) {
- const Collection = require('../collection');
- // Check the collection name
- checkCollectionName(newName);
- // Build the command
- const renameCollection = `${coll.s.dbName}.${coll.s.name}`;
- const toCollection = `${coll.s.dbName}.${newName}`;
- const dropTarget = typeof options.dropTarget === 'boolean' ? options.dropTarget : false;
- const cmd = { renameCollection: renameCollection, to: toCollection, dropTarget: dropTarget };
-
- // Decorate command with writeConcern if supported
- applyWriteConcern(cmd, { db: coll.s.db, collection: coll }, options);
-
- // Execute against admin
- executeDbAdminCommand(coll.s.db.admin().s.db, cmd, options, (err, doc) => {
- if (err) return handleCallback(callback, err, null);
- // We have an error
- if (doc.errmsg) return handleCallback(callback, toError(doc), null);
- try {
- return handleCallback(
- callback,
- null,
- new Collection(
- coll.s.db,
- coll.s.topology,
- coll.s.dbName,
- newName,
- coll.s.pkFactory,
- coll.s.options
- )
- );
- } catch (err) {
- return handleCallback(callback, toError(err), null);
- }
- });
- }
-
- /**
- * Replace a document in the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter The Filter used to select the document to update
- * @param {object} doc The Document that replaces the matching document
- * @param {object} [options] Optional settings. See Collection.prototype.replaceOne for a list of options.
- * @param {Collection~updateWriteOpCallback} [callback] The command result callback
- */
- function replaceOne(coll, filter, doc, options, callback) {
- // Set single document update
- options.multi = false;
-
- // Execute update
- updateDocuments(coll, filter, doc, options, (err, r) => {
- if (callback == null) return;
- if (err && callback) return callback(err);
- if (r == null) return callback(null, { result: { ok: 1 } });
-
- r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
- r.upsertedId =
- Array.isArray(r.result.upserted) && r.result.upserted.length > 0
- ? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
- : null;
- r.upsertedCount =
- Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
- r.matchedCount =
- Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
- r.ops = [doc];
- if (callback) callback(null, r);
- });
- }
-
- /**
- * Save a document.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} doc Document to save
- * @param {object} [options] Optional settings. See Collection.prototype.save for a list of options.
- * @param {Collection~writeOpCallback} [callback] The command result callback
- * @deprecated use insertOne, insertMany, updateOne or updateMany
- */
- function save(coll, doc, options, callback) {
- // Get the write concern options
- const finalOptions = applyWriteConcern(
- Object.assign({}, options),
- { db: coll.s.db, collection: coll },
- options
- );
- // Establish if we need to perform an insert or update
- if (doc._id != null) {
- finalOptions.upsert = true;
- return updateDocuments(coll, { _id: doc._id }, doc, finalOptions, callback);
- }
-
- // Insert the document
- insertDocuments(coll, [doc], finalOptions, (err, result) => {
- if (callback == null) return;
- if (doc == null) return handleCallback(callback, null, null);
- if (err) return handleCallback(callback, err, null);
- handleCallback(callback, null, result);
- });
- }
-
- /**
- * Get all the collection statistics.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} [options] Optional settings. See Collection.prototype.stats for a list of options.
- * @param {Collection~resultCallback} [callback] The collection result callback
- */
- function stats(coll, options, callback) {
- // Build command object
- const commandObject = {
- collStats: coll.s.name
- };
-
- // Check if we have the scale value
- if (options['scale'] != null) commandObject['scale'] = options['scale'];
-
- options = Object.assign({}, options);
- // Ensure we have the right read preference inheritance
- options.readPreference = resolveReadPreference(options, { db: coll.s.db, collection: coll });
-
- // Execute the command
- executeCommand(coll.s.db, commandObject, options, callback);
- }
-
- function updateCallback(err, r, callback) {
- if (callback == null) return;
- if (err) return callback(err);
- if (r == null) return callback(null, { result: { ok: 1 } });
- r.modifiedCount = r.result.nModified != null ? r.result.nModified : r.result.n;
- r.upsertedId =
- Array.isArray(r.result.upserted) && r.result.upserted.length > 0
- ? r.result.upserted[0] // FIXME(major): should be `r.result.upserted[0]._id`
- : null;
- r.upsertedCount =
- Array.isArray(r.result.upserted) && r.result.upserted.length ? r.result.upserted.length : 0;
- r.matchedCount =
- Array.isArray(r.result.upserted) && r.result.upserted.length > 0 ? 0 : r.result.n;
- callback(null, r);
- }
-
- function updateDocuments(coll, selector, document, options, callback) {
- if ('function' === typeof options) (callback = options), (options = null);
- if (options == null) options = {};
- if (!('function' === typeof callback)) callback = null;
-
- // If we are not providing a selector or document throw
- if (selector == null || typeof selector !== 'object')
- return callback(toError('selector must be a valid JavaScript object'));
- if (document == null || typeof document !== 'object')
- return callback(toError('document must be a valid JavaScript object'));
-
- // Final options for retryable writes and write concern
- let finalOptions = Object.assign({}, options);
- finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
- finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);
-
- // Do we return the actual result document
- // Either use override on the function, or go back to default on either the collection
- // level or db
- finalOptions.serializeFunctions = options.serializeFunctions || coll.s.serializeFunctions;
-
- // Execute the operation
- const op = { q: selector, u: document };
- op.upsert = options.upsert !== void 0 ? !!options.upsert : false;
- op.multi = options.multi !== void 0 ? !!options.multi : false;
-
- if (finalOptions.arrayFilters) {
- op.arrayFilters = finalOptions.arrayFilters;
- delete finalOptions.arrayFilters;
- }
-
- if (finalOptions.retryWrites && op.multi) {
- finalOptions.retryWrites = false;
- }
-
- // Have we specified collation
- try {
- decorateWithCollation(finalOptions, coll, options);
- } catch (err) {
- return callback(err, null);
- }
-
- // Update options
- coll.s.topology.update(coll.s.namespace, [op], finalOptions, (err, result) => {
- if (callback == null) return;
- if (err) return handleCallback(callback, err, null);
- if (result == null) return handleCallback(callback, null, null);
- if (result.result.code) return handleCallback(callback, toError(result.result));
- if (result.result.writeErrors)
- return handleCallback(callback, toError(result.result.writeErrors[0]));
- // Return the results
- handleCallback(callback, null, result);
- });
- }
-
- /**
- * Update multiple documents in the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter The Filter used to select the documents to update
- * @param {object} update The update operations to be applied to the document
- * @param {object} [options] Optional settings. See Collection.prototype.updateMany for a list of options.
- * @param {Collection~updateWriteOpCallback} [callback] The command result callback
- */
- function updateMany(coll, filter, update, options, callback) {
- // Set single document update
- options.multi = true;
- // Execute update
- updateDocuments(coll, filter, update, options, (err, r) => updateCallback(err, r, callback));
- }
-
- /**
- * Update a single document in the collection.
- *
- * @method
- * @param {Collection} a Collection instance.
- * @param {object} filter The Filter used to select the document to update
- * @param {object} update The update operations to be applied to the document
- * @param {object} [options] Optional settings. See Collection.prototype.updateOne for a list of options.
- * @param {Collection~updateWriteOpCallback} [callback] The command result callback
- */
- function updateOne(coll, filter, update, options, callback) {
- // Set single document update
- options.multi = false;
- // Execute update
- updateDocuments(coll, filter, update, options, (err, r) => updateCallback(err, r, callback));
- }
-
- module.exports = {
- bulkWrite,
- checkForAtomicOperators,
- count,
- countDocuments,
- buildCountCommand,
- createIndex,
- createIndexes,
- deleteMany,
- deleteOne,
- distinct,
- dropIndex,
- dropIndexes,
- ensureIndex,
- findAndModify,
- findAndRemove,
- findOne,
- findOneAndDelete,
- findOneAndReplace,
- findOneAndUpdate,
- geoHaystackSearch,
- group,
- indexes,
- indexExists,
- indexInformation,
- insertOne,
- isCapped,
- mapReduce,
- optionsOp,
- parallelCollectionScan,
- prepareDocs,
- reIndex,
- removeDocuments,
- rename,
- replaceOne,
- save,
- stats,
- updateDocuments,
- updateMany,
- updateOne
- };
|