summaryrefslogtreecommitdiff
path: root/src/mongo/shell/db.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/shell/db.js')
-rw-r--r--src/mongo/shell/db.js3218
1 files changed, 1601 insertions, 1617 deletions
diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js
index a309bda09d2..afc6e5357ed 100644
--- a/src/mongo/shell/db.js
+++ b/src/mongo/shell/db.js
@@ -4,1854 +4,1838 @@ var DB;
(function() {
- var _defaultWriteConcern = {w: 'majority', wtimeout: 10 * 60 * 1000};
+var _defaultWriteConcern = {w: 'majority', wtimeout: 10 * 60 * 1000};
- if (DB === undefined) {
- DB = function(mongo, name) {
- this._mongo = mongo;
- this._name = name;
- };
- }
-
- DB.prototype.getMongo = function() {
- assert(this._mongo, "why no mongo!");
- return this._mongo;
+if (DB === undefined) {
+ DB = function(mongo, name) {
+ this._mongo = mongo;
+ this._name = name;
};
+}
- DB.prototype.getSiblingDB = function(name) {
- return this.getSession().getDatabase(name);
- };
+DB.prototype.getMongo = function() {
+ assert(this._mongo, "why no mongo!");
+ return this._mongo;
+};
- DB.prototype.getSisterDB = DB.prototype.getSiblingDB;
+DB.prototype.getSiblingDB = function(name) {
+ return this.getSession().getDatabase(name);
+};
- DB.prototype.getName = function() {
- return this._name;
- };
+DB.prototype.getSisterDB = DB.prototype.getSiblingDB;
- DB.prototype.stats = function(scale) {
- return this.runCommand({dbstats: 1, scale: scale});
- };
+DB.prototype.getName = function() {
+ return this._name;
+};
- DB.prototype.getCollection = function(name) {
- return new DBCollection(this._mongo, this, name, this._name + "." + name);
- };
+DB.prototype.stats = function(scale) {
+ return this.runCommand({dbstats: 1, scale: scale});
+};
- DB.prototype.commandHelp = function(name) {
- var c = {};
- c[name] = 1;
- c.help = true;
- var res = this.runCommand(c);
- if (!res.ok)
- throw _getErrorWithCode(res, res.errmsg);
- return res.help;
- };
+DB.prototype.getCollection = function(name) {
+ return new DBCollection(this._mongo, this, name, this._name + "." + name);
+};
- // utility to attach readPreference if needed.
- DB.prototype._attachReadPreferenceToCommand = function(cmdObj, readPref) {
- "use strict";
- // if the user has not set a readpref, return the original cmdObj
- if ((readPref === null) || typeof(readPref) !== "object") {
- return cmdObj;
- }
-
- // if user specifies $readPreference manually, then don't change it
- if (cmdObj.hasOwnProperty("$readPreference")) {
- return cmdObj;
- }
+DB.prototype.commandHelp = function(name) {
+ var c = {};
+ c[name] = 1;
+ c.help = true;
+ var res = this.runCommand(c);
+ if (!res.ok)
+ throw _getErrorWithCode(res, res.errmsg);
+ return res.help;
+};
+
+// utility to attach readPreference if needed.
+DB.prototype._attachReadPreferenceToCommand = function(cmdObj, readPref) {
+ "use strict";
+ // if the user has not set a readpref, return the original cmdObj
+ if ((readPref === null) || typeof (readPref) !== "object") {
+ return cmdObj;
+ }
- // copy object so we don't mutate the original
- var clonedCmdObj = Object.extend({}, cmdObj);
- // The server selection spec mandates that the key is '$query', but
- // the shell has historically used 'query'. The server accepts both,
- // so we maintain the existing behavior
- var cmdObjWithReadPref = {query: clonedCmdObj, $readPreference: readPref};
- return cmdObjWithReadPref;
- };
+ // if user specifies $readPreference manually, then don't change it
+ if (cmdObj.hasOwnProperty("$readPreference")) {
+ return cmdObj;
+ }
- /**
- * If someone passes i.e. runCommand("foo", {bar: "baz"}), we merge it in to
- * runCommand({foo: 1, bar: "baz"}).
- * If we already have a command object in the first argument, we ensure that the second
- * argument 'extraKeys' is either null or an empty object. This prevents users from accidentally
- * calling runCommand({foo: 1}, {bar: 1}) and expecting the final command invocation to be
- * runCommand({foo: 1, bar: 1}).
- * This helper abstracts that logic.
- */
- DB.prototype._mergeCommandOptions = function(obj, extraKeys) {
- "use strict";
-
- if (typeof(obj) === "object") {
- if (Object.keys(extraKeys || {}).length > 0) {
- throw Error("Unexpected second argument to DB.runCommand(): (type: " +
- typeof(extraKeys) + "): " + tojson(extraKeys));
- }
- return obj;
- } else if (typeof(obj) !== "string") {
- throw Error("First argument to DB.runCommand() must be either an object or a string: " +
- "(type: " + typeof(obj) + "): " + tojson(obj));
- }
+ // copy object so we don't mutate the original
+ var clonedCmdObj = Object.extend({}, cmdObj);
+ // The server selection spec mandates that the key is '$query', but
+ // the shell has historically used 'query'. The server accepts both,
+ // so we maintain the existing behavior
+ var cmdObjWithReadPref = {query: clonedCmdObj, $readPreference: readPref};
+ return cmdObjWithReadPref;
+};
+
+/**
+ * If someone passes i.e. runCommand("foo", {bar: "baz"}), we merge it in to
+ * runCommand({foo: 1, bar: "baz"}).
+ * If we already have a command object in the first argument, we ensure that the second
+ * argument 'extraKeys' is either null or an empty object. This prevents users from accidentally
+ * calling runCommand({foo: 1}, {bar: 1}) and expecting the final command invocation to be
+ * runCommand({foo: 1, bar: 1}).
+ * This helper abstracts that logic.
+ */
+DB.prototype._mergeCommandOptions = function(obj, extraKeys) {
+ "use strict";
+
+ if (typeof (obj) === "object") {
+ if (Object.keys(extraKeys || {}).length > 0) {
+ throw Error("Unexpected second argument to DB.runCommand(): (type: " +
+ typeof (extraKeys) + "): " + tojson(extraKeys));
+ }
+ return obj;
+ } else if (typeof (obj) !== "string") {
+ throw Error("First argument to DB.runCommand() must be either an object or a string: " +
+ "(type: " + typeof (obj) + "): " + tojson(obj));
+ }
- var commandName = obj;
- var mergedCmdObj = {};
- mergedCmdObj[commandName] = 1;
-
- if (!extraKeys) {
- return mergedCmdObj;
- } else if (typeof(extraKeys) === "object") {
- // this will traverse the prototype chain of extra, but keeping
- // to maintain legacy behavior
- for (var key in extraKeys) {
- mergedCmdObj[key] = extraKeys[key];
- }
- } else {
- throw Error("Second argument to DB.runCommand(" + commandName +
- ") must be an object: (type: " + typeof(extraKeys) + "): " +
- tojson(extraKeys));
- }
+ var commandName = obj;
+ var mergedCmdObj = {};
+ mergedCmdObj[commandName] = 1;
+ if (!extraKeys) {
return mergedCmdObj;
- };
-
- // Like runCommand but applies readPreference if one has been set
- // on the connection. Also sets slaveOk if a (non-primary) readPref has been set.
- DB.prototype.runReadCommand = function(obj, extra, queryOptions) {
- "use strict";
-
- // Support users who call this function with a string commandName, e.g.
- // db.runReadCommand("commandName", {arg1: "value", arg2: "value"}).
- obj = this._mergeCommandOptions(obj, extra);
- queryOptions = queryOptions !== undefined ? queryOptions : this.getQueryOptions();
+ } else if (typeof (extraKeys) === "object") {
+ // this will traverse the prototype chain of extra, but keeping
+ // to maintain legacy behavior
+ for (var key in extraKeys) {
+ mergedCmdObj[key] = extraKeys[key];
+ }
+ } else {
+ throw Error("Second argument to DB.runCommand(" + commandName +
+ ") must be an object: (type: " + typeof (extraKeys) +
+ "): " + tojson(extraKeys));
+ }
- {
- const session = this.getSession();
+ return mergedCmdObj;
+};
- const readPreference = session._getSessionAwareClient().getReadPreference(session);
- if (readPreference !== null) {
- obj = this._attachReadPreferenceToCommand(obj, readPreference);
+// Like runCommand but applies readPreference if one has been set
+// on the connection. Also sets slaveOk if a (non-primary) readPref has been set.
+DB.prototype.runReadCommand = function(obj, extra, queryOptions) {
+ "use strict";
- if (readPreference.mode !== "primary") {
- // Set slaveOk if readPrefMode has been explicitly set with a readPreference
- // other than primary.
- queryOptions |= 4;
- }
- }
- }
+ // Support users who call this function with a string commandName, e.g.
+ // db.runReadCommand("commandName", {arg1: "value", arg2: "value"}).
+ obj = this._mergeCommandOptions(obj, extra);
+ queryOptions = queryOptions !== undefined ? queryOptions : this.getQueryOptions();
- // The 'extra' parameter is not used as we have already created a merged command object.
- return this.runCommand(obj, null, queryOptions);
- };
-
- // runCommand uses this impl to actually execute the command
- DB.prototype._runCommandImpl = function(name, obj, options) {
+ {
const session = this.getSession();
- return session._getSessionAwareClient().runCommand(session, name, obj, options);
- };
- DB.prototype.runCommand = function(obj, extra, queryOptions) {
- "use strict";
+ const readPreference = session._getSessionAwareClient().getReadPreference(session);
+ if (readPreference !== null) {
+ obj = this._attachReadPreferenceToCommand(obj, readPreference);
- // Support users who call this function with a string commandName, e.g.
- // db.runCommand("commandName", {arg1: "value", arg2: "value"}).
- var mergedObj = this._mergeCommandOptions(obj, extra);
-
- // if options were passed (i.e. because they were overridden on a collection), use them.
- // Otherwise use getQueryOptions.
- var options =
- (typeof(queryOptions) !== "undefined") ? queryOptions : this.getQueryOptions();
-
- try {
- return this._runCommandImpl(this._name, mergedObj, options);
- } catch (ex) {
- // When runCommand flowed through query, a connection error resulted in the message
- // "error doing query: failed". Even though this message is arguably incorrect
- // for a command failing due to a connection failure, we preserve it for backwards
- // compatibility. See SERVER-18334 for details.
- if (ex.message.indexOf("network error") >= 0) {
- throw new Error("error doing query: failed: " + ex.message);
+ if (readPreference.mode !== "primary") {
+ // Set slaveOk if readPrefMode has been explicitly set with a readPreference
+ // other than primary.
+ queryOptions |= 4;
}
- throw ex;
}
- };
-
- DB.prototype.runCommandWithMetadata = function(commandArgs, metadata) {
- const session = this.getSession();
- return session._getSessionAwareClient().runCommandWithMetadata(
- session, this._name, metadata, commandArgs);
- };
+ }
- DB.prototype._dbCommand = DB.prototype.runCommand;
- DB.prototype._dbReadCommand = DB.prototype.runReadCommand;
+ // The 'extra' parameter is not used as we have already created a merged command object.
+ return this.runCommand(obj, null, queryOptions);
+};
+
+// runCommand uses this impl to actually execute the command
+DB.prototype._runCommandImpl = function(name, obj, options) {
+ const session = this.getSession();
+ return session._getSessionAwareClient().runCommand(session, name, obj, options);
+};
+
+DB.prototype.runCommand = function(obj, extra, queryOptions) {
+ "use strict";
+
+ // Support users who call this function with a string commandName, e.g.
+ // db.runCommand("commandName", {arg1: "value", arg2: "value"}).
+ var mergedObj = this._mergeCommandOptions(obj, extra);
+
+ // if options were passed (i.e. because they were overridden on a collection), use them.
+ // Otherwise use getQueryOptions.
+ var options = (typeof (queryOptions) !== "undefined") ? queryOptions : this.getQueryOptions();
+
+ try {
+ return this._runCommandImpl(this._name, mergedObj, options);
+ } catch (ex) {
+ // When runCommand flowed through query, a connection error resulted in the message
+ // "error doing query: failed". Even though this message is arguably incorrect
+ // for a command failing due to a connection failure, we preserve it for backwards
+ // compatibility. See SERVER-18334 for details.
+ if (ex.message.indexOf("network error") >= 0) {
+ throw new Error("error doing query: failed: " + ex.message);
+ }
+ throw ex;
+ }
+};
- DB.prototype.adminCommand = function(obj, extra) {
- if (this._name == "admin")
- return this.runCommand(obj, extra);
- return this.getSiblingDB("admin").runCommand(obj, extra);
- };
+DB.prototype.runCommandWithMetadata = function(commandArgs, metadata) {
+ const session = this.getSession();
+ return session._getSessionAwareClient().runCommandWithMetadata(
+ session, this._name, metadata, commandArgs);
+};
- DB.prototype._adminCommand = DB.prototype.adminCommand; // alias old name
+DB.prototype._dbCommand = DB.prototype.runCommand;
+DB.prototype._dbReadCommand = DB.prototype.runReadCommand;
- DB.prototype._runAggregate = function(cmdObj, aggregateOptions) {
- assert(cmdObj.pipeline instanceof Array, "cmdObj must contain a 'pipeline' array");
- assert(cmdObj.aggregate !== undefined, "cmdObj must contain 'aggregate' field");
- assert(aggregateOptions === undefined || aggregateOptions instanceof Object,
- "'aggregateOptions' argument must be an object");
+DB.prototype.adminCommand = function(obj, extra) {
+ if (this._name == "admin")
+ return this.runCommand(obj, extra);
+ return this.getSiblingDB("admin").runCommand(obj, extra);
+};
- // Make a copy of the initial command object, i.e. {aggregate: x, pipeline: [...]}.
- cmdObj = Object.extend({}, cmdObj);
+DB.prototype._adminCommand = DB.prototype.adminCommand; // alias old name
- // Make a copy of the aggregation options.
- let optcpy = Object.extend({}, (aggregateOptions || {}));
+DB.prototype._runAggregate = function(cmdObj, aggregateOptions) {
+ assert(cmdObj.pipeline instanceof Array, "cmdObj must contain a 'pipeline' array");
+ assert(cmdObj.aggregate !== undefined, "cmdObj must contain 'aggregate' field");
+ assert(aggregateOptions === undefined || aggregateOptions instanceof Object,
+ "'aggregateOptions' argument must be an object");
- if ('batchSize' in optcpy) {
- if (optcpy.cursor == null) {
- optcpy.cursor = {};
- }
+ // Make a copy of the initial command object, i.e. {aggregate: x, pipeline: [...]}.
+ cmdObj = Object.extend({}, cmdObj);
- optcpy.cursor.batchSize = optcpy['batchSize'];
- delete optcpy['batchSize'];
- } else if ('useCursor' in optcpy) {
- if (optcpy.cursor == null) {
- optcpy.cursor = {};
- }
+ // Make a copy of the aggregation options.
+ let optcpy = Object.extend({}, (aggregateOptions || {}));
- delete optcpy['useCursor'];
+ if ('batchSize' in optcpy) {
+ if (optcpy.cursor == null) {
+ optcpy.cursor = {};
}
- const maxAwaitTimeMS = optcpy.maxAwaitTimeMS;
- delete optcpy.maxAwaitTimeMS;
-
- // Reassign the cleaned-up options.
- aggregateOptions = optcpy;
-
- // Add the options to the command object.
- Object.extend(cmdObj, aggregateOptions);
-
- if (!('cursor' in cmdObj)) {
- cmdObj.cursor = {};
+ optcpy.cursor.batchSize = optcpy['batchSize'];
+ delete optcpy['batchSize'];
+ } else if ('useCursor' in optcpy) {
+ if (optcpy.cursor == null) {
+ optcpy.cursor = {};
}
- const pipeline = cmdObj.pipeline;
-
- // Check whether the pipeline has a stage which performs writes like $out. If not, we may
- // run on a Secondary and should attach a readPreference.
- const hasWritingStage = (function() {
- if (pipeline.length == 0) {
- return false;
- }
- const lastStage = pipeline[pipeline.length - 1];
- return lastStage.hasOwnProperty("$out") || lastStage.hasOwnProperty("$merge");
- }());
-
- const doAgg = function(cmdObj) {
- return hasWritingStage ? this.runCommand(cmdObj) : this.runReadCommand(cmdObj);
- }.bind(this);
-
- const res = doAgg(cmdObj);
+ delete optcpy['useCursor'];
+ }
- if (!res.ok && (res.code == 17020 || res.errmsg == "unrecognized field \"cursor") &&
- !("cursor" in aggregateOptions)) {
- // If the command failed because cursors aren't supported and the user didn't explicitly
- // request a cursor, try again without requesting a cursor.
- delete cmdObj.cursor;
+ const maxAwaitTimeMS = optcpy.maxAwaitTimeMS;
+ delete optcpy.maxAwaitTimeMS;
- res = doAgg(cmdObj);
+ // Reassign the cleaned-up options.
+ aggregateOptions = optcpy;
- if ('result' in res && !("cursor" in res)) {
- // convert old-style output to cursor-style output
- res.cursor = {ns: '', id: NumberLong(0)};
- res.cursor.firstBatch = res.result;
- delete res.result;
- }
- }
+ // Add the options to the command object.
+ Object.extend(cmdObj, aggregateOptions);
- assert.commandWorked(res, "aggregate failed");
-
- if ("cursor" in res) {
- let batchSizeValue = undefined;
+ if (!('cursor' in cmdObj)) {
+ cmdObj.cursor = {};
+ }
- if (cmdObj["cursor"]["batchSize"] > 0) {
- batchSizeValue = cmdObj["cursor"]["batchSize"];
- }
+ const pipeline = cmdObj.pipeline;
- return new DBCommandCursor(this, res, batchSizeValue, maxAwaitTimeMS);
+ // Check whether the pipeline has a stage which performs writes like $out. If not, we may
+ // run on a Secondary and should attach a readPreference.
+ const hasWritingStage = (function() {
+ if (pipeline.length == 0) {
+ return false;
}
+ const lastStage = pipeline[pipeline.length - 1];
+ return lastStage.hasOwnProperty("$out") || lastStage.hasOwnProperty("$merge");
+ }());
- return res;
- };
-
- DB.prototype.aggregate = function(pipeline, aggregateOptions) {
- assert(pipeline instanceof Array, "pipeline argument must be an array");
- const cmdObj = this._mergeCommandOptions("aggregate", {pipeline: pipeline});
-
- return this._runAggregate(cmdObj, (aggregateOptions || {}));
- };
-
- /**
- Create a new collection in the database. Normally, collection creation is automatic. You
- would
- use this function if you wish to specify special options on creation.
-
- If the collection already exists, no action occurs.
-
- <p>Options:</p>
- <ul>
- <li>
- size: desired initial extent size for the collection. Must be <= 1000000000.
- for fixed size (capped) collections, this size is the total/max size of the
- collection.
- </li>
- <li>
- capped: if true, this is a capped collection (where old data rolls out).
- </li>
- <li> max: maximum number of objects if capped (optional).</li>
- <li>
- storageEngine: BSON document containing storage engine specific options. Format:
- {
- storageEngine: {
- storageEngine1: {
- ...
- },
- storageEngine2: {
- ...
- },
- ...
- }
- }
- </li>
- </ul>
+ const doAgg = function(cmdObj) {
+ return hasWritingStage ? this.runCommand(cmdObj) : this.runReadCommand(cmdObj);
+ }.bind(this);
- <p>Example:</p>
- <code>db.createCollection("movies", { size: 10 * 1024 * 1024, capped:true } );</code>
+ const res = doAgg(cmdObj);
- * @param {String} name Name of new collection to create
- * @param {Object} options Object with options for call. Options are listed above.
- * @return {Object} returned has member ok set to true if operation succeeds, false otherwise.
- */
- DB.prototype.createCollection = function(name, opt) {
- var options = opt || {};
+ if (!res.ok && (res.code == 17020 || res.errmsg == "unrecognized field \"cursor") &&
+ !("cursor" in aggregateOptions)) {
+ // If the command failed because cursors aren't supported and the user didn't explicitly
+ // request a cursor, try again without requesting a cursor.
+ delete cmdObj.cursor;
- var cmd = {create: name};
- Object.extend(cmd, options);
-
- return this._dbCommand(cmd);
- };
+ res = doAgg(cmdObj);
- /**
- * Command to create a view based on the specified aggregation pipeline.
- * Usage: db.createView(name, viewOn, pipeline: [{ $operator: {...}}, ... ])
- *
- * @param name String - name of the new view to create
- * @param viewOn String - name of the backing view or collection
- * @param pipeline [{ $operator: {...}}, ... ] - the aggregation pipeline that defines the view
- * @param options { } - options on the view, e.g., collations
- */
- DB.prototype.createView = function(name, viewOn, pipeline, opt) {
- var options = opt || {};
-
- var cmd = {create: name};
-
- if (viewOn == undefined) {
- throw Error("Must specify a backing view or collection");
+ if ('result' in res && !("cursor" in res)) {
+ // convert old-style output to cursor-style output
+ res.cursor = {ns: '', id: NumberLong(0)};
+ res.cursor.firstBatch = res.result;
+ delete res.result;
}
+ }
- // Since we allow a single stage pipeline to be specified as an object
- // in aggregation, we need to account for that here for consistency.
- if (pipeline != undefined) {
- if (!Array.isArray(pipeline)) {
- pipeline = [pipeline];
- }
- }
- options.pipeline = pipeline;
- options.viewOn = viewOn;
-
- Object.extend(cmd, options);
+ assert.commandWorked(res, "aggregate failed");
- return this._dbCommand(cmd);
- };
+ if ("cursor" in res) {
+ let batchSizeValue = undefined;
- /**
- * @deprecated use getProfilingStatus
- * Returns the current profiling level of this database
- * @return SOMETHING_FIXME or null on error
- */
- DB.prototype.getProfilingLevel = function() {
- var res = assert.commandWorked(this._dbCommand({profile: -1}));
- return res ? res.was : null;
- };
+ if (cmdObj["cursor"]["batchSize"] > 0) {
+ batchSizeValue = cmdObj["cursor"]["batchSize"];
+ }
- /**
- * @return the current profiling status
- * example { was : 0, slowms : 100 }
- * @return SOMETHING_FIXME or null on error
- */
- DB.prototype.getProfilingStatus = function() {
- var res = this._dbCommand({profile: -1});
- if (!res.ok)
- throw _getErrorWithCode(res, "profile command failed: " + tojson(res));
- delete res.ok;
- return res;
- };
+ return new DBCommandCursor(this, res, batchSizeValue, maxAwaitTimeMS);
+ }
- /**
- * Erase the entire database.
- * @params writeConcern: (document) expresses the write concern of the drop command.
- * @return Object returned has member ok set to true if operation succeeds, false otherwise.
- */
- DB.prototype.dropDatabase = function(writeConcern) {
- return this._dbCommand(
- {dropDatabase: 1, writeConcern: writeConcern ? writeConcern : _defaultWriteConcern});
- };
+ return res;
+};
+
+DB.prototype.aggregate = function(pipeline, aggregateOptions) {
+ assert(pipeline instanceof Array, "pipeline argument must be an array");
+ const cmdObj = this._mergeCommandOptions("aggregate", {pipeline: pipeline});
+
+ return this._runAggregate(cmdObj, (aggregateOptions || {}));
+};
+
+/**
+ Create a new collection in the database. Normally, collection creation is automatic. You
+ would
+ use this function if you wish to specify special options on creation.
+
+ If the collection already exists, no action occurs.
+
+ <p>Options:</p>
+ <ul>
+ <li>
+ size: desired initial extent size for the collection. Must be <= 1000000000.
+ for fixed size (capped) collections, this size is the total/max size of the
+ collection.
+ </li>
+ <li>
+ capped: if true, this is a capped collection (where old data rolls out).
+ </li>
+ <li> max: maximum number of objects if capped (optional).</li>
+ <li>
+ storageEngine: BSON document containing storage engine specific options. Format:
+ {
+ storageEngine: {
+ storageEngine1: {
+ ...
+ },
+ storageEngine2: {
+ ...
+ },
+ ...
+ }
+ }
+ </li>
+ </ul>
+
+ <p>Example:</p>
+ <code>db.createCollection("movies", { size: 10 * 1024 * 1024, capped:true } );</code>
+
+ * @param {String} name Name of new collection to create
+ * @param {Object} options Object with options for call. Options are listed above.
+ * @return {Object} returned has member ok set to true if operation succeeds, false otherwise.
+*/
+DB.prototype.createCollection = function(name, opt) {
+ var options = opt || {};
+
+ var cmd = {create: name};
+ Object.extend(cmd, options);
+
+ return this._dbCommand(cmd);
+};
+
+/**
+ * Command to create a view based on the specified aggregation pipeline.
+ * Usage: db.createView(name, viewOn, pipeline: [{ $operator: {...}}, ... ])
+ *
+ * @param name String - name of the new view to create
+ * @param viewOn String - name of the backing view or collection
+ * @param pipeline [{ $operator: {...}}, ... ] - the aggregation pipeline that defines the view
+ * @param options { } - options on the view, e.g., collations
+ */
+DB.prototype.createView = function(name, viewOn, pipeline, opt) {
+ var options = opt || {};
+
+ var cmd = {create: name};
+
+ if (viewOn == undefined) {
+ throw Error("Must specify a backing view or collection");
+ }
- /**
- * Shuts down the database. Must be run while using the admin database.
- * @param opts Options for shutdown. Possible options are:
- * - force: (boolean) if the server should shut down, even if there is no
- * up-to-date slave
- * - timeoutSecs: (number) the server will continue checking over timeoutSecs
- * if any other servers have caught up enough for it to shut down.
- */
- DB.prototype.shutdownServer = function(opts) {
- if ("admin" != this._name) {
- return "shutdown command only works with the admin database; try 'use admin'";
+ // Since we allow a single stage pipeline to be specified as an object
+ // in aggregation, we need to account for that here for consistency.
+ if (pipeline != undefined) {
+ if (!Array.isArray(pipeline)) {
+ pipeline = [pipeline];
}
+ }
+ options.pipeline = pipeline;
+ options.viewOn = viewOn;
+
+ Object.extend(cmd, options);
+
+ return this._dbCommand(cmd);
+};
+
+/**
+ * @deprecated use getProfilingStatus
+ * Returns the current profiling level of this database
+ * @return SOMETHING_FIXME or null on error
+ */
+DB.prototype.getProfilingLevel = function() {
+ var res = assert.commandWorked(this._dbCommand({profile: -1}));
+ return res ? res.was : null;
+};
+
+/**
+ * @return the current profiling status
+ * example { was : 0, slowms : 100 }
+ * @return SOMETHING_FIXME or null on error
+ */
+DB.prototype.getProfilingStatus = function() {
+ var res = this._dbCommand({profile: -1});
+ if (!res.ok)
+ throw _getErrorWithCode(res, "profile command failed: " + tojson(res));
+ delete res.ok;
+ return res;
+};
+
+/**
+ * Erase the entire database.
+ * @params writeConcern: (document) expresses the write concern of the drop command.
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+ */
+DB.prototype.dropDatabase = function(writeConcern) {
+ return this._dbCommand(
+ {dropDatabase: 1, writeConcern: writeConcern ? writeConcern : _defaultWriteConcern});
+};
+
+/**
+ * Shuts down the database. Must be run while using the admin database.
+ * @param opts Options for shutdown. Possible options are:
+ * - force: (boolean) if the server should shut down, even if there is no
+ * up-to-date slave
+ * - timeoutSecs: (number) the server will continue checking over timeoutSecs
+ * if any other servers have caught up enough for it to shut down.
+ */
+DB.prototype.shutdownServer = function(opts) {
+ if ("admin" != this._name) {
+ return "shutdown command only works with the admin database; try 'use admin'";
+ }
- var cmd = {'shutdown': 1};
- opts = opts || {};
- for (var o in opts) {
- cmd[o] = opts[o];
- }
+ var cmd = {'shutdown': 1};
+ opts = opts || {};
+ for (var o in opts) {
+ cmd[o] = opts[o];
+ }
- try {
- var res = this.runCommand(cmd);
- if (!res.ok) {
- throw _getErrorWithCode(res, 'shutdownServer failed: ' + tojson(res));
- }
- throw Error('shutdownServer failed: server is still up.');
- } catch (e) {
- // we expect the command to not return a response, as the server will shut down
- // immediately.
- if (isNetworkError(e)) {
- print('server should be down...');
- return;
- }
- throw e;
+ try {
+ var res = this.runCommand(cmd);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, 'shutdownServer failed: ' + tojson(res));
+ }
+ throw Error('shutdownServer failed: server is still up.');
+ } catch (e) {
+ // we expect the command to not return a response, as the server will shut down
+ // immediately.
+ if (isNetworkError(e)) {
+ print('server should be down...');
+ return;
}
- };
+ throw e;
+ }
+};
+
+/**
+ Clone database on another server to here. This functionality was removed as of MongoDB 4.2.
+ The shell helper is kept to maintain compatibility with previous versions of MongoDB.
+ <p>
+ Generally, you should dropDatabase() first as otherwise the cloned information will MERGE
+ into whatever data is already present in this database. (That is however a valid way to use
+ clone if you are trying to do something intentionally, such as union three non-overlapping
+ databases into one.)
+ <p>
+ This is a low level administrative function will is not typically used.
+
+ * @param {String} from Where to clone from (dbhostname[:port]). May not be this database
+ (self) as you cannot clone to yourself.
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+ * See also: db.copyDatabase()
+ */
+DB.prototype.cloneDatabase = function(from) {
+ print(
+ "WARNING: db.cloneDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone");
+ assert(isString(from) && from.length);
+ return this._dbCommand({clone: from});
+};
+
+/**
+ Copy database from one server or name to another server or name. This functionality was
+ removed as of MongoDB 4.2. The shell helper is kept to maintain compatibility with previous
+ versions of MongoDB.
+
+ Generally, you should dropDatabase() first as otherwise the copied information will MERGE
+ into whatever data is already present in this database (and you will get duplicate objects
+ in collections potentially.)
+
+ For security reasons this function only works when executed on the "admin" db. However,
+ if you have access to said db, you can copy any database from one place to another.
+
+ This method provides a way to "rename" a database by copying it to a new db name and
+ location. Additionally, it effectively provides a repair facility.
+
+ * @param {String} fromdb database name from which to copy.
+ * @param {String} todb database name to copy to.
+ * @param {String} fromhost hostname of the database (and optionally, ":port") from which to
+ copy the data. default if unspecified is to copy from self.
+ * @return Object returned has member ok set to true if operation succeeds, false otherwise.
+ * See also: db.clone()
+*/
+DB.prototype.copyDatabase = function(
+ fromdb, todb, fromhost, username, password, mechanism, slaveOk) {
+ print(
+ "WARNING: db.copyDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone");
+ assert(isString(fromdb) && fromdb.length);
+ assert(isString(todb) && todb.length);
+ fromhost = fromhost || "";
+ if ((typeof username === "boolean") && (typeof password === "undefined") &&
+ (typeof mechanism === "undefined") && (typeof slaveOk === "undefined")) {
+ slaveOk = username;
+ username = undefined;
+ }
+ if (typeof slaveOk !== "boolean") {
+ slaveOk = false;
+ }
- /**
- Clone database on another server to here. This functionality was removed as of MongoDB 4.2.
- The shell helper is kept to maintain compatibility with previous versions of MongoDB.
- <p>
- Generally, you should dropDatabase() first as otherwise the cloned information will MERGE
- into whatever data is already present in this database. (That is however a valid way to use
- clone if you are trying to do something intentionally, such as union three non-overlapping
- databases into one.)
- <p>
- This is a low level administrative function will is not typically used.
-
- * @param {String} from Where to clone from (dbhostname[:port]). May not be this database
- (self) as you cannot clone to yourself.
- * @return Object returned has member ok set to true if operation succeeds, false otherwise.
- * See also: db.copyDatabase()
- */
- DB.prototype.cloneDatabase = function(from) {
- print(
- "WARNING: db.cloneDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone");
- assert(isString(from) && from.length);
- return this._dbCommand({clone: from});
- };
+ if (!mechanism) {
+ mechanism = this._getDefaultAuthenticationMechanism(username, fromdb);
+ }
+ assert(mechanism == "SCRAM-SHA-1" || mechanism == "SCRAM-SHA-256" || mechanism == "MONGODB-CR");
- /**
- Copy database from one server or name to another server or name. This functionality was
- removed as of MongoDB 4.2. The shell helper is kept to maintain compatibility with previous
- versions of MongoDB.
-
- Generally, you should dropDatabase() first as otherwise the copied information will MERGE
- into whatever data is already present in this database (and you will get duplicate objects
- in collections potentially.)
-
- For security reasons this function only works when executed on the "admin" db. However,
- if you have access to said db, you can copy any database from one place to another.
-
- This method provides a way to "rename" a database by copying it to a new db name and
- location. Additionally, it effectively provides a repair facility.
-
- * @param {String} fromdb database name from which to copy.
- * @param {String} todb database name to copy to.
- * @param {String} fromhost hostname of the database (and optionally, ":port") from which to
- copy the data. default if unspecified is to copy from self.
- * @return Object returned has member ok set to true if operation succeeds, false otherwise.
- * See also: db.clone()
- */
- DB.prototype.copyDatabase = function(
- fromdb, todb, fromhost, username, password, mechanism, slaveOk) {
- print(
- "WARNING: db.copyDatabase will only function with MongoDB 4.0 and below. See http://dochub.mongodb.org/core/4.2-copydb-clone");
- assert(isString(fromdb) && fromdb.length);
- assert(isString(todb) && todb.length);
- fromhost = fromhost || "";
- if ((typeof username === "boolean") && (typeof password === "undefined") &&
- (typeof mechanism === "undefined") && (typeof slaveOk === "undefined")) {
- slaveOk = username;
- username = undefined;
- }
- if (typeof slaveOk !== "boolean") {
- slaveOk = false;
- }
+ // Check for no auth or copying from localhost
+ if (!username || !password || fromhost == "") {
+ return this._adminCommand(
+ {copydb: 1, fromhost: fromhost, fromdb: fromdb, todb: todb, slaveOk: slaveOk});
+ }
- if (!mechanism) {
- mechanism = this._getDefaultAuthenticationMechanism(username, fromdb);
- }
- assert(mechanism == "SCRAM-SHA-1" || mechanism == "SCRAM-SHA-256" ||
- mechanism == "MONGODB-CR");
+ // Use the copyDatabase native helper for SCRAM-SHA-1/256
+ if (mechanism != "MONGODB-CR") {
+ // TODO SERVER-30886: Add session support for Mongo.prototype.copyDatabaseWithSCRAM().
+ return this.getMongo().copyDatabaseWithSCRAM(
+ fromdb, todb, fromhost, username, password, slaveOk);
+ }
- // Check for no auth or copying from localhost
- if (!username || !password || fromhost == "") {
- return this._adminCommand(
- {copydb: 1, fromhost: fromhost, fromdb: fromdb, todb: todb, slaveOk: slaveOk});
+ // Fall back to MONGODB-CR
+ var n = assert.commandWorked(this._adminCommand({copydbgetnonce: 1, fromhost: fromhost}));
+ return this._adminCommand({
+ copydb: 1,
+ fromhost: fromhost,
+ fromdb: fromdb,
+ todb: todb,
+ username: username,
+ nonce: n.nonce,
+ key: this.__pwHash(n.nonce, username, password),
+ slaveOk: slaveOk,
+ });
+};
+
+DB.prototype.help = function() {
+ print("DB methods:");
+ print(
+ "\tdb.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)]");
+ print(
+ "\tdb.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor");
+ print("\tdb.auth(username, password)");
+ print("\tdb.cloneDatabase(fromhost) - will only function with MongoDB 4.0 and below");
+ print("\tdb.commandHelp(name) returns the help for the command");
+ print(
+ "\tdb.copyDatabase(fromdb, todb, fromhost) - will only function with MongoDB 4.0 and below");
+ print("\tdb.createCollection(name, {size: ..., capped: ..., max: ...})");
+ print("\tdb.createUser(userDocument)");
+ print("\tdb.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})");
+ print("\tdb.currentOp() displays currently executing operations in the db");
+ print("\tdb.dropDatabase(writeConcern)");
+ print("\tdb.dropUser(username)");
+ print("\tdb.eval() - deprecated");
+ print("\tdb.fsyncLock() flush data to disk and lock server for backups");
+ print("\tdb.fsyncUnlock() unlocks server following a db.fsyncLock()");
+ print("\tdb.getCollection(cname) same as db['cname'] or db.cname");
+ print("\tdb.getCollectionInfos([filter]) - returns a list that contains the names and options" +
+ " of the db's collections");
+ print("\tdb.getCollectionNames()");
+ print("\tdb.getLastError() - just returns the err msg string");
+ print("\tdb.getLastErrorObj() - return full status object");
+ print("\tdb.getLogComponents()");
+ print("\tdb.getMongo() get the server connection object");
+ print("\tdb.getMongo().setSlaveOk() allow queries on a replication slave server");
+ print("\tdb.getName()");
+ print("\tdb.getProfilingLevel() - deprecated");
+ print("\tdb.getProfilingStatus() - returns if profiling is on and slow threshold");
+ print("\tdb.getReplicationInfo()");
+ print("\tdb.getSiblingDB(name) get the db at the same server as this one");
+ print(
+ "\tdb.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set");
+ print("\tdb.hostInfo() get details about the server's host");
+ print("\tdb.isMaster() check replica primary status");
+ print("\tdb.killOp(opid) kills the current operation in the db");
+ print("\tdb.listCommands() lists all the db commands");
+ print("\tdb.loadServerScripts() loads all the scripts in db.system.js");
+ print("\tdb.logout()");
+ print("\tdb.printCollectionStats()");
+ print("\tdb.printReplicationInfo()");
+ print("\tdb.printShardingStatus()");
+ print("\tdb.printSlaveReplicationInfo()");
+ print("\tdb.resetError()");
+ print(
+ "\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into {cmdObj: 1}");
+ print("\tdb.serverStatus()");
+ print("\tdb.setLogLevel(level,<component>)");
+ print("\tdb.setProfilingLevel(level,slowms) 0=off 1=slow 2=all");
+ print("\tdb.setVerboseShell(flag) display extra information in shell output");
+ print(
+ "\tdb.setWriteConcern(<write concern doc>) - sets the write concern for writes to the db");
+ print("\tdb.shutdownServer()");
+ print("\tdb.stats()");
+ print(
+ "\tdb.unsetWriteConcern(<write concern doc>) - unsets the write concern for writes to the db");
+ print("\tdb.version() current version of the server");
+ print("\tdb.watch() - opens a change stream cursor for a database to report on all " +
+ " changes to its non-system collections.");
+ return __magicNoPrint;
+};
+
+DB.prototype.printCollectionStats = function(scale) {
+ if (arguments.length > 1) {
+ print("printCollectionStats() has a single optional argument (scale)");
+ return;
+ }
+ if (typeof scale != 'undefined') {
+ if (typeof scale != 'number') {
+ print("scale has to be a number >= 1");
+ return;
}
-
- // Use the copyDatabase native helper for SCRAM-SHA-1/256
- if (mechanism != "MONGODB-CR") {
- // TODO SERVER-30886: Add session support for Mongo.prototype.copyDatabaseWithSCRAM().
- return this.getMongo().copyDatabaseWithSCRAM(
- fromdb, todb, fromhost, username, password, slaveOk);
+ if (scale < 1) {
+ print("scale has to be >= 1");
+ return;
}
+ }
+ var mydb = this;
+ this.getCollectionNames().forEach(function(z) {
+ print(z);
+ printjson(mydb.getCollection(z).stats(scale));
+ print("---");
+ });
+};
+
+/**
+ * Configures settings for capturing operations inside the system.profile collection and in the
+ * slow query log.
+ *
+ * The 'level' can be 0, 1, or 2:
+ * - 0 means that profiling is off and nothing will be written to system.profile.
+ * - 1 means that profiling is on for operations slower than the currently configured 'slowms'
+ * threshold (more on 'slowms' below).
+ * - 2 means that profiling is on for all operations, regardless of whether or not they are
+ * slower than 'slowms'.
+ *
+ * The 'options' parameter, if a number, is interpreted as the 'slowms' value to send to the
+ * server. 'slowms' determines the threshold, in milliseconds, above which slow operations get
+ * profiled at profiling level 1 or logged at logLevel 0.
+ *
+ * If 'options' is not a number, it is expected to be an object containing additional parameters
+ * to get passed to the server. For example, db.setProfilingLevel(2, {foo: "bar"}) will issue
+ * the command {profile: 2, foo: "bar"} to the server.
+ */
+DB.prototype.setProfilingLevel = function(level, options) {
+ if (level < 0 || level > 2) {
+ var errorText = "input level " + level + " is out of range [0..2]";
+ var errorObject = new Error(errorText);
+ errorObject['dbSetProfilingException'] = errorText;
+ throw errorObject;
+ }
- // Fall back to MONGODB-CR
- var n = assert.commandWorked(this._adminCommand({copydbgetnonce: 1, fromhost: fromhost}));
- return this._adminCommand({
- copydb: 1,
- fromhost: fromhost,
- fromdb: fromdb,
- todb: todb,
- username: username,
- nonce: n.nonce,
- key: this.__pwHash(n.nonce, username, password),
- slaveOk: slaveOk,
- });
- };
-
- DB.prototype.help = function() {
- print("DB methods:");
- print(
- "\tdb.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)]");
- print(
- "\tdb.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor");
- print("\tdb.auth(username, password)");
- print("\tdb.cloneDatabase(fromhost) - will only function with MongoDB 4.0 and below");
- print("\tdb.commandHelp(name) returns the help for the command");
- print(
- "\tdb.copyDatabase(fromdb, todb, fromhost) - will only function with MongoDB 4.0 and below");
- print("\tdb.createCollection(name, {size: ..., capped: ..., max: ...})");
- print("\tdb.createUser(userDocument)");
- print("\tdb.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})");
- print("\tdb.currentOp() displays currently executing operations in the db");
- print("\tdb.dropDatabase(writeConcern)");
- print("\tdb.dropUser(username)");
- print("\tdb.eval() - deprecated");
- print("\tdb.fsyncLock() flush data to disk and lock server for backups");
- print("\tdb.fsyncUnlock() unlocks server following a db.fsyncLock()");
- print("\tdb.getCollection(cname) same as db['cname'] or db.cname");
- print(
- "\tdb.getCollectionInfos([filter]) - returns a list that contains the names and options" +
- " of the db's collections");
- print("\tdb.getCollectionNames()");
- print("\tdb.getLastError() - just returns the err msg string");
- print("\tdb.getLastErrorObj() - return full status object");
- print("\tdb.getLogComponents()");
- print("\tdb.getMongo() get the server connection object");
- print("\tdb.getMongo().setSlaveOk() allow queries on a replication slave server");
- print("\tdb.getName()");
- print("\tdb.getProfilingLevel() - deprecated");
- print("\tdb.getProfilingStatus() - returns if profiling is on and slow threshold");
- print("\tdb.getReplicationInfo()");
- print("\tdb.getSiblingDB(name) get the db at the same server as this one");
- print(
- "\tdb.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set");
- print("\tdb.hostInfo() get details about the server's host");
- print("\tdb.isMaster() check replica primary status");
- print("\tdb.killOp(opid) kills the current operation in the db");
- print("\tdb.listCommands() lists all the db commands");
- print("\tdb.loadServerScripts() loads all the scripts in db.system.js");
- print("\tdb.logout()");
- print("\tdb.printCollectionStats()");
- print("\tdb.printReplicationInfo()");
- print("\tdb.printShardingStatus()");
- print("\tdb.printSlaveReplicationInfo()");
- print("\tdb.resetError()");
- print(
- "\tdb.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into {cmdObj: 1}");
- print("\tdb.serverStatus()");
- print("\tdb.setLogLevel(level,<component>)");
- print("\tdb.setProfilingLevel(level,slowms) 0=off 1=slow 2=all");
- print("\tdb.setVerboseShell(flag) display extra information in shell output");
- print(
- "\tdb.setWriteConcern(<write concern doc>) - sets the write concern for writes to the db");
- print("\tdb.shutdownServer()");
- print("\tdb.stats()");
- print(
- "\tdb.unsetWriteConcern(<write concern doc>) - unsets the write concern for writes to the db");
- print("\tdb.version() current version of the server");
- print("\tdb.watch() - opens a change stream cursor for a database to report on all " +
- " changes to its non-system collections.");
- return __magicNoPrint;
- };
+ var cmd = {profile: level};
+ if (isNumber(options)) {
+ cmd.slowms = options;
+ } else {
+ cmd = Object.extend(cmd, options);
+ }
+ return assert.commandWorked(this._dbCommand(cmd));
+};
+
+/**
+ * @deprecated
+ * <p> Evaluate a js expression at the database server.</p>
+ *
+ * <p>Useful if you need to touch a lot of data lightly; in such a scenario
+ * the network transfer of the data could be a bottleneck. A good example
+ * is "select count(*)" -- can be done server side via this mechanism.
+ * </p>
+ *
+ * <p>
+ * If the eval fails, an exception is thrown of the form:
+ * </p>
+ * <code>{ dbEvalException: { retval: functionReturnValue, ok: num [, errno: num] [, errmsg:
+ *str] } }</code>
+ *
+ * <p>Example: </p>
+ * <code>print( "mycount: " + db.eval( function(){db.mycoll.find({},{_id:ObjId()}).length();}
+ *);</code>
+ *
+ * @param {Function} jsfunction Javascript function to run on server. Note this it not a
+ *closure, but rather just "code".
+ * @return result of your function, or null if error
+ *
+ */
+DB.prototype.eval = function(jsfunction) {
+ print("WARNING: db.eval is deprecated");
+
+ var cmd = {$eval: jsfunction};
+ if (arguments.length > 1) {
+ cmd.args = Array.from(arguments).slice(1);
+ }
- DB.prototype.printCollectionStats = function(scale) {
- if (arguments.length > 1) {
- print("printCollectionStats() has a single optional argument (scale)");
- return;
- }
- if (typeof scale != 'undefined') {
- if (typeof scale != 'number') {
- print("scale has to be a number >= 1");
- return;
- }
- if (scale < 1) {
- print("scale has to be >= 1");
- return;
+ var res = this._dbCommand(cmd);
+
+ if (!res.ok)
+ throw _getErrorWithCode(res, tojson(res));
+
+ return res.retval;
+};
+
+DB.prototype.dbEval = DB.prototype.eval;
+
+/**
+ * <p>
+ * An array of grouped items is returned. The array must fit in RAM, thus this function is not
+ * suitable when the return set is extremely large.
+ * </p>
+ * <p>
+ * To order the grouped data, simply sort it client side upon return.
+ * <p>
+ Defaults
+ cond may be null if you want to run against all rows in the collection
+ keyf is a function which takes an object and returns the desired key. set either key or
+ keyf (not both).
+ * </p>
+ */
+DB.prototype.groupeval = function(parmsObj) {
+ var groupFunction = function() {
+ var parms = args[0];
+ var c = db[parms.ns].find(parms.cond || {});
+ var map = new Map();
+ var pks = parms.key ? Object.keySet(parms.key) : null;
+ var pkl = pks ? pks.length : 0;
+ var key = {};
+
+ while (c.hasNext()) {
+ var obj = c.next();
+ if (pks) {
+ for (var i = 0; i < pkl; i++) {
+ var k = pks[i];
+ key[k] = obj[k];
+ }
+ } else {
+ key = parms.$keyf(obj);
}
- }
- var mydb = this;
- this.getCollectionNames().forEach(function(z) {
- print(z);
- printjson(mydb.getCollection(z).stats(scale));
- print("---");
- });
- };
- /**
- * Configures settings for capturing operations inside the system.profile collection and in the
- * slow query log.
- *
- * The 'level' can be 0, 1, or 2:
- * - 0 means that profiling is off and nothing will be written to system.profile.
- * - 1 means that profiling is on for operations slower than the currently configured 'slowms'
- * threshold (more on 'slowms' below).
- * - 2 means that profiling is on for all operations, regardless of whether or not they are
- * slower than 'slowms'.
- *
- * The 'options' parameter, if a number, is interpreted as the 'slowms' value to send to the
- * server. 'slowms' determines the threshold, in milliseconds, above which slow operations get
- * profiled at profiling level 1 or logged at logLevel 0.
- *
- * If 'options' is not a number, it is expected to be an object containing additional parameters
- * to get passed to the server. For example, db.setProfilingLevel(2, {foo: "bar"}) will issue
- * the command {profile: 2, foo: "bar"} to the server.
- */
- DB.prototype.setProfilingLevel = function(level, options) {
- if (level < 0 || level > 2) {
- var errorText = "input level " + level + " is out of range [0..2]";
- var errorObject = new Error(errorText);
- errorObject['dbSetProfilingException'] = errorText;
- throw errorObject;
+ var aggObj = map.get(key);
+ if (aggObj == null) {
+ var newObj = Object.extend({}, key); // clone
+ aggObj = Object.extend(newObj, parms.initial);
+ map.put(key, aggObj);
+ }
+ parms.$reduce(obj, aggObj);
}
- var cmd = {profile: level};
- if (isNumber(options)) {
- cmd.slowms = options;
- } else {
- cmd = Object.extend(cmd, options);
- }
- return assert.commandWorked(this._dbCommand(cmd));
+ return map.values();
};
- /**
- * @deprecated
- * <p> Evaluate a js expression at the database server.</p>
- *
- * <p>Useful if you need to touch a lot of data lightly; in such a scenario
- * the network transfer of the data could be a bottleneck. A good example
- * is "select count(*)" -- can be done server side via this mechanism.
- * </p>
- *
- * <p>
- * If the eval fails, an exception is thrown of the form:
- * </p>
- * <code>{ dbEvalException: { retval: functionReturnValue, ok: num [, errno: num] [, errmsg:
- *str] } }</code>
- *
- * <p>Example: </p>
- * <code>print( "mycount: " + db.eval( function(){db.mycoll.find({},{_id:ObjId()}).length();}
- *);</code>
- *
- * @param {Function} jsfunction Javascript function to run on server. Note this it not a
- *closure, but rather just "code".
- * @return result of your function, or null if error
- *
- */
- DB.prototype.eval = function(jsfunction) {
- print("WARNING: db.eval is deprecated");
-
- var cmd = {$eval: jsfunction};
- if (arguments.length > 1) {
- cmd.args = Array.from(arguments).slice(1);
- }
+ return this.eval(groupFunction, this._groupFixParms(parmsObj));
+};
- var res = this._dbCommand(cmd);
+DB.prototype._groupFixParms = function(parmsObj) {
+ var parms = Object.extend({}, parmsObj);
- if (!res.ok)
- throw _getErrorWithCode(res, tojson(res));
+ if (parms.reduce) {
+ parms.$reduce = parms.reduce; // must have $ to pass to db
+ delete parms.reduce;
+ }
- return res.retval;
- };
+ if (parms.keyf) {
+ parms.$keyf = parms.keyf;
+ delete parms.keyf;
+ }
- DB.prototype.dbEval = DB.prototype.eval;
-
- /**
- * <p>
- * An array of grouped items is returned. The array must fit in RAM, thus this function is not
- * suitable when the return set is extremely large.
- * </p>
- * <p>
- * To order the grouped data, simply sort it client side upon return.
- * <p>
- Defaults
- cond may be null if you want to run against all rows in the collection
- keyf is a function which takes an object and returns the desired key. set either key or
- keyf (not both).
- * </p>
- */
- DB.prototype.groupeval = function(parmsObj) {
-
- var groupFunction = function() {
- var parms = args[0];
- var c = db[parms.ns].find(parms.cond || {});
- var map = new Map();
- var pks = parms.key ? Object.keySet(parms.key) : null;
- var pkl = pks ? pks.length : 0;
- var key = {};
-
- while (c.hasNext()) {
- var obj = c.next();
- if (pks) {
- for (var i = 0; i < pkl; i++) {
- var k = pks[i];
- key[k] = obj[k];
- }
- } else {
- key = parms.$keyf(obj);
- }
+ return parms;
+};
+
+DB.prototype.resetError = function() {
+ return this.runCommand({reseterror: 1});
+};
+
+DB.prototype.forceError = function() {
+ return this.runCommand({forceerror: 1});
+};
+
+DB.prototype.getLastError = function(w, wtimeout) {
+ var res = this.getLastErrorObj(w, wtimeout);
+ if (!res.ok)
+ throw _getErrorWithCode(ret, "getlasterror failed: " + tojson(res));
+ return res.err;
+};
+DB.prototype.getLastErrorObj = function(w, wtimeout, j) {
+ var cmd = {getlasterror: 1};
+ if (w) {
+ cmd.w = w;
+ if (wtimeout)
+ cmd.wtimeout = wtimeout;
+ if (j != null)
+ cmd.j = j;
+ }
+ var res = this.runCommand(cmd);
+
+ if (!res.ok)
+ throw _getErrorWithCode(res, "getlasterror failed: " + tojson(res));
+ return res;
+};
+DB.prototype.getLastErrorCmd = DB.prototype.getLastErrorObj;
+
+DB.prototype._getCollectionInfosCommand = function(
+ filter, nameOnly = false, authorizedCollections = false, options = {}) {
+ filter = filter || {};
+ const cmd = {
+ listCollections: 1,
+ filter: filter,
+ nameOnly: nameOnly,
+ authorizedCollections: authorizedCollections
+ };
+
+ const res = this.runCommand(Object.merge(cmd, options));
+ if (!res.ok) {
+ throw _getErrorWithCode(res, "listCollections failed: " + tojson(res));
+ }
- var aggObj = map.get(key);
- if (aggObj == null) {
- var newObj = Object.extend({}, key); // clone
- aggObj = Object.extend(newObj, parms.initial);
- map.put(key, aggObj);
- }
- parms.$reduce(obj, aggObj);
- }
+ return new DBCommandCursor(this, res).toArray().sort(compareOn("name"));
+};
- return map.values();
- };
+DB.prototype._getCollectionInfosFromPrivileges = function() {
+ let ret = this.runCommand({connectionStatus: 1, showPrivileges: 1});
+ if (!ret.ok) {
+ throw _getErrorWithCode(res, "Failed to acquire collection information from privileges");
+ }
- return this.eval(groupFunction, this._groupFixParms(parmsObj));
- };
+ // Parse apart collection information.
+ let result = [];
- DB.prototype._groupFixParms = function(parmsObj) {
- var parms = Object.extend({}, parmsObj);
+ let privileges = ret.authInfo.authenticatedUserPrivileges;
+ if (privileges === undefined) {
+ return result;
+ }
- if (parms.reduce) {
- parms.$reduce = parms.reduce; // must have $ to pass to db
- delete parms.reduce;
+ privileges.forEach(privilege => {
+ let resource = privilege.resource;
+ if (resource === undefined) {
+ return;
}
-
- if (parms.keyf) {
- parms.$keyf = parms.keyf;
- delete parms.keyf;
+ let db = resource.db;
+ if (db === undefined || db !== this.getName()) {
+ return;
}
-
- return parms;
- };
-
- DB.prototype.resetError = function() {
- return this.runCommand({reseterror: 1});
- };
-
- DB.prototype.forceError = function() {
- return this.runCommand({forceerror: 1});
- };
-
- DB.prototype.getLastError = function(w, wtimeout) {
- var res = this.getLastErrorObj(w, wtimeout);
- if (!res.ok)
- throw _getErrorWithCode(ret, "getlasterror failed: " + tojson(res));
- return res.err;
- };
- DB.prototype.getLastErrorObj = function(w, wtimeout, j) {
- var cmd = {getlasterror: 1};
- if (w) {
- cmd.w = w;
- if (wtimeout)
- cmd.wtimeout = wtimeout;
- if (j != null)
- cmd.j = j;
+ let collection = resource.collection;
+ if (collection === undefined || typeof collection !== "string" || collection === "") {
+ return;
}
- var res = this.runCommand(cmd);
- if (!res.ok)
- throw _getErrorWithCode(res, "getlasterror failed: " + tojson(res));
- return res;
- };
- DB.prototype.getLastErrorCmd = DB.prototype.getLastErrorObj;
-
- DB.prototype._getCollectionInfosCommand = function(
- filter, nameOnly = false, authorizedCollections = false, options = {}) {
- filter = filter || {};
- const cmd = {
- listCollections: 1,
- filter: filter,
- nameOnly: nameOnly,
- authorizedCollections: authorizedCollections
- };
-
- const res = this.runCommand(Object.merge(cmd, options));
- if (!res.ok) {
- throw _getErrorWithCode(res, "listCollections failed: " + tojson(res));
+ result.push({name: collection});
+ });
+
+ return result.sort(compareOn("name"));
+};
+
+/**
+ * Returns a list that contains the names and options of this database's collections, sorted
+ * by collection name. An optional filter can be specified to match only collections with
+ * certain metadata.
+ */
+DB.prototype.getCollectionInfos = function(
+ filter, nameOnly = false, authorizedCollections = false) {
+ try {
+ return this._getCollectionInfosCommand(filter, nameOnly, authorizedCollections);
+ } catch (ex) {
+ if (ex.code !== ErrorCodes.Unauthorized) {
+ // We cannot recover from this error, propagate it.
+ throw ex;
}
- return new DBCommandCursor(this, res).toArray().sort(compareOn("name"));
- };
+ // We may be able to compute a set of *some* collections which exist and we have access
+ // to from our privileges. For this to work, the previous operation must have failed due
+ // to authorization, we must be attempting to recover the names of our own collections,
+ // and no filter can have been provided.
- DB.prototype._getCollectionInfosFromPrivileges = function() {
- let ret = this.runCommand({connectionStatus: 1, showPrivileges: 1});
- if (!ret.ok) {
- throw _getErrorWithCode(res,
- "Failed to acquire collection information from privileges");
+ if (nameOnly && authorizedCollections && Object.getOwnPropertyNames(filter).length === 0 &&
+ ex.code === ErrorCodes.Unauthorized) {
+ print(
+ "Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus");
+ return this._getCollectionInfosFromPrivileges();
}
- // Parse apart collection information.
- let result = [];
+ throw ex;
+ }
+};
+
+DB.prototype._getCollectionNamesInternal = function(options) {
+ return this._getCollectionInfosCommand({}, true, true, options).map(function(infoObj) {
+ return infoObj.name;
+ });
+};
+
+/**
+ * Returns this database's list of collection names in sorted order.
+ */
+DB.prototype.getCollectionNames = function() {
+ return this._getCollectionNamesInternal({});
+};
+
+DB.prototype.tojson = function() {
+ return this._name;
+};
+
+DB.prototype.toString = function() {
+ return this._name;
+};
+
+DB.prototype.isMaster = function() {
+ return this.runCommand("isMaster");
+};
+
+var commandUnsupported = function(res) {
+ return (!res.ok &&
+ (res.errmsg.startsWith("no such cmd") || res.errmsg.startsWith("no such command") ||
+ res.code === 59 /* CommandNotFound */));
+};
+
+DB.prototype.currentOp = function(arg) {
+ var q = {};
+ if (arg) {
+ if (typeof (arg) == "object")
+ Object.extend(q, arg);
+ else if (arg)
+ q["$all"] = true;
+ }
- let privileges = ret.authInfo.authenticatedUserPrivileges;
- if (privileges === undefined) {
- return result;
+ var commandObj = {"currentOp": 1};
+ Object.extend(commandObj, q);
+ var res = this.adminCommand(commandObj);
+ if (commandUnsupported(res)) {
+ // always send legacy currentOp with default (null) read preference (SERVER-17951)
+ const session = this.getSession();
+ const readPreference = session.getOptions().getReadPreference();
+ try {
+ session.getOptions().setReadPreference(null);
+ res = this.getSiblingDB("admin").$cmd.sys.inprog.findOne(q);
+ } finally {
+ session.getOptions().setReadPreference(readPreference);
}
-
- privileges.forEach(privilege => {
- let resource = privilege.resource;
- if (resource === undefined) {
- return;
- }
- let db = resource.db;
- if (db === undefined || db !== this.getName()) {
- return;
- }
- let collection = resource.collection;
- if (collection === undefined || typeof collection !== "string" || collection === "") {
- return;
- }
-
- result.push({name: collection});
- });
-
- return result.sort(compareOn("name"));
- };
-
- /**
- * Returns a list that contains the names and options of this database's collections, sorted
- * by collection name. An optional filter can be specified to match only collections with
- * certain metadata.
- */
- DB.prototype.getCollectionInfos = function(
- filter, nameOnly = false, authorizedCollections = false) {
+ }
+ return res;
+};
+DB.prototype.currentOP = DB.prototype.currentOp;
+
+DB.prototype.killOp = function(op) {
+ if (!op)
+ throw Error("no opNum to kill specified");
+ var res = this.adminCommand({'killOp': 1, 'op': op});
+ if (commandUnsupported(res)) {
+ // fall back for old servers
+ const session = this.getSession();
+ const readPreference = session.getOptions().getReadPreference();
try {
- return this._getCollectionInfosCommand(filter, nameOnly, authorizedCollections);
- } catch (ex) {
- if (ex.code !== ErrorCodes.Unauthorized) {
- // We cannot recover from this error, propagate it.
- throw ex;
- }
-
- // We may be able to compute a set of *some* collections which exist and we have access
- // to from our privileges. For this to work, the previous operation must have failed due
- // to authorization, we must be attempting to recover the names of our own collections,
- // and no filter can have been provided.
-
- if (nameOnly && authorizedCollections &&
- Object.getOwnPropertyNames(filter).length === 0 &&
- ex.code === ErrorCodes.Unauthorized) {
- print(
- "Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus");
- return this._getCollectionInfosFromPrivileges();
- }
-
- throw ex;
+ session.getOptions().setReadPreference(null);
+ res = this.getSiblingDB("admin").$cmd.sys.killop.findOne({'op': op});
+ } finally {
+ session.getOptions().setReadPreference(readPreference);
}
- };
-
- DB.prototype._getCollectionNamesInternal = function(options) {
- return this._getCollectionInfosCommand({}, true, true, options).map(function(infoObj) {
- return infoObj.name;
- });
- };
-
- /**
- * Returns this database's list of collection names in sorted order.
- */
- DB.prototype.getCollectionNames = function() {
- return this._getCollectionNamesInternal({});
- };
+ }
+ return res;
+};
+DB.prototype.killOP = DB.prototype.killOp;
+
+DB.tsToSeconds = function(x) {
+ if (x.t && x.i)
+ return x.t;
+ return x / 4294967296; // low 32 bits are ordinal #s within a second
+};
+
+/**
+ Get a replication log information summary.
+ <p>
+ This command is for the database/cloud administer and not applicable to most databases.
+ It is only used with the local database. One might invoke from the JS shell:
+ <pre>
+ use local
+ db.getReplicationInfo();
+ </pre>
+ * @return Object timeSpan: time span of the oplog from start to end if slave is more out
+ * of date than that, it can't recover without a complete resync
+*/
+DB.prototype.getReplicationInfo = function() {
+ var localdb = this.getSiblingDB("local");
+
+ var result = {};
+ var oplog;
+ var localCollections = localdb.getCollectionNames();
+ if (localCollections.indexOf('oplog.rs') >= 0) {
+ oplog = 'oplog.rs';
+ } else {
+ result.errmsg = "replication not detected";
+ return result;
+ }
- DB.prototype.tojson = function() {
- return this._name;
- };
+ var ol = localdb.getCollection(oplog);
+ var ol_stats = ol.stats();
+ if (ol_stats && ol_stats.maxSize) {
+ result.logSizeMB = ol_stats.maxSize / (1024 * 1024);
+ } else {
+ result.errmsg = "Could not get stats for local." + oplog + " collection. " +
+ "collstats returned: " + tojson(ol_stats);
+ return result;
+ }
- DB.prototype.toString = function() {
- return this._name;
- };
+ result.usedMB = ol_stats.size / (1024 * 1024);
+ result.usedMB = Math.ceil(result.usedMB * 100) / 100;
- DB.prototype.isMaster = function() {
- return this.runCommand("isMaster");
- };
+ var firstc = ol.find().sort({$natural: 1}).limit(1);
+ var lastc = ol.find().sort({$natural: -1}).limit(1);
+ if (!firstc.hasNext() || !lastc.hasNext()) {
+ result.errmsg =
+ "objects not found in local.oplog.$main -- is this a new and empty db instance?";
+ result.oplogMainRowCount = ol.count();
+ return result;
+ }
- var commandUnsupported = function(res) {
- return (!res.ok &&
- (res.errmsg.startsWith("no such cmd") || res.errmsg.startsWith("no such command") ||
- res.code === 59 /* CommandNotFound */));
- };
+ var first = firstc.next();
+ var last = lastc.next();
+ var tfirst = first.ts;
+ var tlast = last.ts;
+
+ if (tfirst && tlast) {
+ tfirst = DB.tsToSeconds(tfirst);
+ tlast = DB.tsToSeconds(tlast);
+ result.timeDiff = tlast - tfirst;
+ result.timeDiffHours = Math.round(result.timeDiff / 36) / 100;
+ result.tFirst = (new Date(tfirst * 1000)).toString();
+ result.tLast = (new Date(tlast * 1000)).toString();
+ result.now = Date();
+ } else {
+ result.errmsg = "ts element not found in oplog objects";
+ }
- DB.prototype.currentOp = function(arg) {
- var q = {};
- if (arg) {
- if (typeof(arg) == "object")
- Object.extend(q, arg);
- else if (arg)
- q["$all"] = true;
- }
+ return result;
+};
- var commandObj = {"currentOp": 1};
- Object.extend(commandObj, q);
- var res = this.adminCommand(commandObj);
- if (commandUnsupported(res)) {
- // always send legacy currentOp with default (null) read preference (SERVER-17951)
- const session = this.getSession();
- const readPreference = session.getOptions().getReadPreference();
- try {
- session.getOptions().setReadPreference(null);
- res = this.getSiblingDB("admin").$cmd.sys.inprog.findOne(q);
- } finally {
- session.getOptions().setReadPreference(readPreference);
- }
- }
- return res;
- };
- DB.prototype.currentOP = DB.prototype.currentOp;
-
- DB.prototype.killOp = function(op) {
- if (!op)
- throw Error("no opNum to kill specified");
- var res = this.adminCommand({'killOp': 1, 'op': op});
- if (commandUnsupported(res)) {
- // fall back for old servers
- const session = this.getSession();
- const readPreference = session.getOptions().getReadPreference();
- try {
- session.getOptions().setReadPreference(null);
- res = this.getSiblingDB("admin").$cmd.sys.killop.findOne({'op': op});
- } finally {
- session.getOptions().setReadPreference(readPreference);
- }
+DB.prototype.printReplicationInfo = function() {
+ var result = this.getReplicationInfo();
+ if (result.errmsg) {
+ var isMaster = this.isMaster();
+ if (isMaster.arbiterOnly) {
+ print("cannot provide replication status from an arbiter.");
+ return;
+ } else if (!isMaster.ismaster) {
+ print("this is a slave, printing slave replication info.");
+ this.printSlaveReplicationInfo();
+ return;
}
- return res;
- };
- DB.prototype.killOP = DB.prototype.killOp;
-
- DB.tsToSeconds = function(x) {
- if (x.t && x.i)
- return x.t;
- return x / 4294967296; // low 32 bits are ordinal #s within a second
- };
-
- /**
- Get a replication log information summary.
- <p>
- This command is for the database/cloud administer and not applicable to most databases.
- It is only used with the local database. One might invoke from the JS shell:
- <pre>
- use local
- db.getReplicationInfo();
- </pre>
- * @return Object timeSpan: time span of the oplog from start to end if slave is more out
- * of date than that, it can't recover without a complete resync
- */
- DB.prototype.getReplicationInfo = function() {
- var localdb = this.getSiblingDB("local");
-
- var result = {};
- var oplog;
- var localCollections = localdb.getCollectionNames();
- if (localCollections.indexOf('oplog.rs') >= 0) {
- oplog = 'oplog.rs';
+ print(tojson(result));
+ return;
+ }
+ print("configured oplog size: " + result.logSizeMB + "MB");
+ print("log length start to end: " + result.timeDiff + "secs (" + result.timeDiffHours + "hrs)");
+ print("oplog first event time: " + result.tFirst);
+ print("oplog last event time: " + result.tLast);
+ print("now: " + result.now);
+};
+
+DB.prototype.printSlaveReplicationInfo = function() {
+ var startOptimeDate = null;
+ var primary = null;
+
+ function getReplLag(st) {
+ assert(startOptimeDate, "how could this be null (getReplLag startOptimeDate)");
+ print("\tsyncedTo: " + st.toString());
+ var ago = (startOptimeDate - st) / 1000;
+ var hrs = Math.round(ago / 36) / 100;
+ var suffix = "";
+ if (primary) {
+ suffix = "primary ";
} else {
- result.errmsg = "replication not detected";
- return result;
+ suffix = "freshest member (no primary available at the moment)";
}
+ print("\t" + Math.round(ago) + " secs (" + hrs + " hrs) behind the " + suffix);
+ }
- var ol = localdb.getCollection(oplog);
- var ol_stats = ol.stats();
- if (ol_stats && ol_stats.maxSize) {
- result.logSizeMB = ol_stats.maxSize / (1024 * 1024);
- } else {
- result.errmsg = "Could not get stats for local." + oplog + " collection. " +
- "collstats returned: " + tojson(ol_stats);
- return result;
+ function getMaster(members) {
+ for (i in members) {
+ var row = members[i];
+ if (row.state === 1) {
+ return row;
+ }
}
- result.usedMB = ol_stats.size / (1024 * 1024);
- result.usedMB = Math.ceil(result.usedMB * 100) / 100;
-
- var firstc = ol.find().sort({$natural: 1}).limit(1);
- var lastc = ol.find().sort({$natural: -1}).limit(1);
- if (!firstc.hasNext() || !lastc.hasNext()) {
- result.errmsg =
- "objects not found in local.oplog.$main -- is this a new and empty db instance?";
- result.oplogMainRowCount = ol.count();
- return result;
- }
+ return null;
+ }
- var first = firstc.next();
- var last = lastc.next();
- var tfirst = first.ts;
- var tlast = last.ts;
-
- if (tfirst && tlast) {
- tfirst = DB.tsToSeconds(tfirst);
- tlast = DB.tsToSeconds(tlast);
- result.timeDiff = tlast - tfirst;
- result.timeDiffHours = Math.round(result.timeDiff / 36) / 100;
- result.tFirst = (new Date(tfirst * 1000)).toString();
- result.tLast = (new Date(tlast * 1000)).toString();
- result.now = Date();
+ function g(x) {
+ assert(x, "how could this be null (printSlaveReplicationInfo gx)");
+ print("source: " + x.host);
+ if (x.syncedTo) {
+ var st = new Date(DB.tsToSeconds(x.syncedTo) * 1000);
+ getReplLag(st);
} else {
- result.errmsg = "ts element not found in oplog objects";
+ print("\tdoing initial sync");
}
+ }
- return result;
- };
-
- DB.prototype.printReplicationInfo = function() {
- var result = this.getReplicationInfo();
- if (result.errmsg) {
- var isMaster = this.isMaster();
- if (isMaster.arbiterOnly) {
- print("cannot provide replication status from an arbiter.");
- return;
- } else if (!isMaster.ismaster) {
- print("this is a slave, printing slave replication info.");
- this.printSlaveReplicationInfo();
- return;
- }
- print(tojson(result));
+ function r(x) {
+ assert(x, "how could this be null (printSlaveReplicationInfo rx)");
+ if (x.state == 1 || x.state == 7) { // ignore primaries (1) and arbiters (7)
return;
}
- print("configured oplog size: " + result.logSizeMB + "MB");
- print("log length start to end: " + result.timeDiff + "secs (" + result.timeDiffHours +
- "hrs)");
- print("oplog first event time: " + result.tFirst);
- print("oplog last event time: " + result.tLast);
- print("now: " + result.now);
- };
- DB.prototype.printSlaveReplicationInfo = function() {
- var startOptimeDate = null;
- var primary = null;
-
- function getReplLag(st) {
- assert(startOptimeDate, "how could this be null (getReplLag startOptimeDate)");
- print("\tsyncedTo: " + st.toString());
- var ago = (startOptimeDate - st) / 1000;
- var hrs = Math.round(ago / 36) / 100;
- var suffix = "";
- if (primary) {
- suffix = "primary ";
- } else {
- suffix = "freshest member (no primary available at the moment)";
- }
- print("\t" + Math.round(ago) + " secs (" + hrs + " hrs) behind the " + suffix);
+ print("source: " + x.name);
+ if (x.optime) {
+ getReplLag(x.optimeDate);
+ } else {
+ print("\tno replication info, yet. State: " + x.stateStr);
}
+ }
- function getMaster(members) {
- for (i in members) {
- var row = members[i];
- if (row.state === 1) {
- return row;
- }
- }
+ var L = this.getSiblingDB("local");
- return null;
+ if (L.system.replset.count() != 0) {
+ var status = this.adminCommand({'replSetGetStatus': 1});
+ primary = getMaster(status.members);
+ if (primary) {
+ startOptimeDate = primary.optimeDate;
}
-
- function g(x) {
- assert(x, "how could this be null (printSlaveReplicationInfo gx)");
- print("source: " + x.host);
- if (x.syncedTo) {
- var st = new Date(DB.tsToSeconds(x.syncedTo) * 1000);
- getReplLag(st);
- } else {
- print("\tdoing initial sync");
+ // no primary, find the most recent op among all members
+ else {
+ startOptimeDate = new Date(0, 0);
+ for (i in status.members) {
+ if (status.members[i].optimeDate > startOptimeDate) {
+ startOptimeDate = status.members[i].optimeDate;
+ }
}
}
- function r(x) {
- assert(x, "how could this be null (printSlaveReplicationInfo rx)");
- if (x.state == 1 || x.state == 7) { // ignore primaries (1) and arbiters (7)
- return;
- }
-
- print("source: " + x.name);
- if (x.optime) {
- getReplLag(x.optimeDate);
- } else {
- print("\tno replication info, yet. State: " + x.stateStr);
- }
+ for (i in status.members) {
+ r(status.members[i]);
}
-
- var L = this.getSiblingDB("local");
-
- if (L.system.replset.count() != 0) {
- var status = this.adminCommand({'replSetGetStatus': 1});
- primary = getMaster(status.members);
- if (primary) {
- startOptimeDate = primary.optimeDate;
- }
- // no primary, find the most recent op among all members
- else {
- startOptimeDate = new Date(0, 0);
- for (i in status.members) {
- if (status.members[i].optimeDate > startOptimeDate) {
- startOptimeDate = status.members[i].optimeDate;
- }
- }
- }
-
- for (i in status.members) {
- r(status.members[i]);
+ }
+};
+
+DB.prototype.serverBuildInfo = function() {
+ return this._adminCommand("buildinfo");
+};
+
+// Used to trim entries from the metrics.commands that have never been executed
+getActiveCommands = function(tree) {
+ var result = {};
+ for (var i in tree) {
+ if (!tree.hasOwnProperty(i))
+ continue;
+ if (tree[i].hasOwnProperty("total")) {
+ if (tree[i].total > 0) {
+ result[i] = tree[i];
}
+ continue;
}
- };
-
- DB.prototype.serverBuildInfo = function() {
- return this._adminCommand("buildinfo");
- };
-
- // Used to trim entries from the metrics.commands that have never been executed
- getActiveCommands = function(tree) {
- var result = {};
- for (var i in tree) {
- if (!tree.hasOwnProperty(i))
- continue;
- if (tree[i].hasOwnProperty("total")) {
- if (tree[i].total > 0) {
- result[i] = tree[i];
- }
- continue;
- }
- if (i == "<UNKNOWN>") {
- if (tree[i] > 0) {
- result[i] = tree[i];
- }
- continue;
- }
- // Handles nested commands
- var subStatus = getActiveCommands(tree[i]);
- if (Object.keys(subStatus).length > 0) {
+ if (i == "<UNKNOWN>") {
+ if (tree[i] > 0) {
result[i] = tree[i];
}
+ continue;
}
- return result;
- };
-
- DB.prototype.serverStatus = function(options) {
- var cmd = {serverStatus: 1};
- if (options) {
- Object.extend(cmd, options);
+ // Handles nested commands
+ var subStatus = getActiveCommands(tree[i]);
+ if (Object.keys(subStatus).length > 0) {
+ result[i] = tree[i];
}
- var res = this._adminCommand(cmd);
- // Only prune if we have a metrics tree with commands.
- if (res.metrics && res.metrics.commands) {
- res.metrics.commands = getActiveCommands(res.metrics.commands);
- }
- return res;
- };
+ }
+ return result;
+};
- DB.prototype.hostInfo = function() {
- return this._adminCommand("hostInfo");
- };
+DB.prototype.serverStatus = function(options) {
+ var cmd = {serverStatus: 1};
+ if (options) {
+ Object.extend(cmd, options);
+ }
+ var res = this._adminCommand(cmd);
+ // Only prune if we have a metrics tree with commands.
+ if (res.metrics && res.metrics.commands) {
+ res.metrics.commands = getActiveCommands(res.metrics.commands);
+ }
+ return res;
+};
- DB.prototype.serverCmdLineOpts = function() {
- return this._adminCommand("getCmdLineOpts");
- };
+DB.prototype.hostInfo = function() {
+ return this._adminCommand("hostInfo");
+};
- DB.prototype.version = function() {
- return this.serverBuildInfo().version;
- };
+DB.prototype.serverCmdLineOpts = function() {
+ return this._adminCommand("getCmdLineOpts");
+};
- DB.prototype.serverBits = function() {
- return this.serverBuildInfo().bits;
- };
+DB.prototype.version = function() {
+ return this.serverBuildInfo().version;
+};
- DB.prototype.listCommands = function() {
- var x = this.runCommand("listCommands");
- for (var name in x.commands) {
- var c = x.commands[name];
+DB.prototype.serverBits = function() {
+ return this.serverBuildInfo().bits;
+};
- var s = name + ": ";
+DB.prototype.listCommands = function() {
+ var x = this.runCommand("listCommands");
+ for (var name in x.commands) {
+ var c = x.commands[name];
- if (c.adminOnly)
- s += " adminOnly ";
- if (c.slaveOk)
- s += " slaveOk ";
+ var s = name + ": ";
- s += "\n ";
- s += c.help.replace(/\n/g, '\n ');
- s += "\n";
+ if (c.adminOnly)
+ s += " adminOnly ";
+ if (c.slaveOk)
+ s += " slaveOk ";
- print(s);
- }
- };
+ s += "\n ";
+ s += c.help.replace(/\n/g, '\n ');
+ s += "\n";
- DB.prototype.printShardingStatus = function(verbose) {
- printShardingStatus(this.getSiblingDB("config"), verbose);
- };
+ print(s);
+ }
+};
- DB.prototype.fsyncLock = function() {
- return this.adminCommand({fsync: 1, lock: true});
- };
+DB.prototype.printShardingStatus = function(verbose) {
+ printShardingStatus(this.getSiblingDB("config"), verbose);
+};
- DB.prototype.fsyncUnlock = function() {
- var res = this.adminCommand({fsyncUnlock: 1});
- if (commandUnsupported(res)) {
- const session = this.getSession();
- const readPreference = session.getOptions().getReadPreference();
- try {
- session.getOptions().setReadPreference(null);
- res = this.getSiblingDB("admin").$cmd.sys.unlock.findOne();
- } finally {
- session.getOptions().setReadPreference(readPreference);
- }
- }
- return res;
- };
+DB.prototype.fsyncLock = function() {
+ return this.adminCommand({fsync: 1, lock: true});
+};
- DB.autocomplete = function(obj) {
- // Time out if a transaction or other op holds locks we need. Caller suppresses exceptions.
- var colls = obj._getCollectionNamesInternal({maxTimeMS: 1000});
- var ret = [];
- for (var i = 0; i < colls.length; i++) {
- if (colls[i].match(/^[a-zA-Z0-9_.\$]+$/))
- ret.push(colls[i]);
+DB.prototype.fsyncUnlock = function() {
+ var res = this.adminCommand({fsyncUnlock: 1});
+ if (commandUnsupported(res)) {
+ const session = this.getSession();
+ const readPreference = session.getOptions().getReadPreference();
+ try {
+ session.getOptions().setReadPreference(null);
+ res = this.getSiblingDB("admin").$cmd.sys.unlock.findOne();
+ } finally {
+ session.getOptions().setReadPreference(readPreference);
}
- return ret;
- };
-
- DB.prototype.setSlaveOk = function(value) {
- if (value == undefined)
- value = true;
- this._slaveOk = value;
- };
-
- DB.prototype.getSlaveOk = function() {
- if (this._slaveOk != undefined)
- return this._slaveOk;
- return this._mongo.getSlaveOk();
- };
-
- DB.prototype.getQueryOptions = function() {
- var options = 0;
- if (this.getSlaveOk())
- options |= 4;
- return options;
- };
-
- /* Loads any scripts contained in system.js into the client shell.
- */
- DB.prototype.loadServerScripts = function() {
- var global = Function('return this')();
- this.system.js.find().forEach(function(u) {
- if (u.value.constructor === Code) {
- global[u._id] = eval("(" + u.value.code + ")");
- } else {
- global[u._id] = u.value;
- }
- });
- };
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////// Security shell helpers below
- /////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////
-
- function getUserObjString(userObj) {
- var pwd = userObj.pwd;
- delete userObj.pwd;
- var toreturn = tojson(userObj);
- userObj.pwd = pwd;
- return toreturn;
}
-
- DB.prototype._modifyCommandToDigestPasswordIfNecessary = function(cmdObj, username) {
- if (!cmdObj["pwd"]) {
- return;
- }
- if (cmdObj.hasOwnProperty("digestPassword")) {
- throw Error(
- "Cannot specify 'digestPassword' through the user management shell helpers, " +
- "use 'passwordDigestor' instead");
- }
- var passwordDigestor = cmdObj["passwordDigestor"] ? cmdObj["passwordDigestor"] : "server";
- if (passwordDigestor == "server") {
- cmdObj["digestPassword"] = true;
- } else if (passwordDigestor == "client") {
- cmdObj["pwd"] = _hashPassword(username, cmdObj["pwd"]);
- cmdObj["digestPassword"] = false;
+ return res;
+};
+
+DB.autocomplete = function(obj) {
+ // Time out if a transaction or other op holds locks we need. Caller suppresses exceptions.
+ var colls = obj._getCollectionNamesInternal({maxTimeMS: 1000});
+ var ret = [];
+ for (var i = 0; i < colls.length; i++) {
+ if (colls[i].match(/^[a-zA-Z0-9_.\$]+$/))
+ ret.push(colls[i]);
+ }
+ return ret;
+};
+
+DB.prototype.setSlaveOk = function(value) {
+ if (value == undefined)
+ value = true;
+ this._slaveOk = value;
+};
+
+DB.prototype.getSlaveOk = function() {
+ if (this._slaveOk != undefined)
+ return this._slaveOk;
+ return this._mongo.getSlaveOk();
+};
+
+DB.prototype.getQueryOptions = function() {
+ var options = 0;
+ if (this.getSlaveOk())
+ options |= 4;
+ return options;
+};
+
+/* Loads any scripts contained in system.js into the client shell.
+ */
+DB.prototype.loadServerScripts = function() {
+ var global = Function('return this')();
+ this.system.js.find().forEach(function(u) {
+ if (u.value.constructor === Code) {
+ global[u._id] = eval("(" + u.value.code + ")");
} else {
- throw Error("'passwordDigestor' must be either 'server' or 'client', got: '" +
- passwordDigestor + "'");
- }
- delete cmdObj["passwordDigestor"];
- };
+ global[u._id] = u.value;
+ }
+ });
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// Security shell helpers below
+/////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+function getUserObjString(userObj) {
+ var pwd = userObj.pwd;
+ delete userObj.pwd;
+ var toreturn = tojson(userObj);
+ userObj.pwd = pwd;
+ return toreturn;
+}
+
+DB.prototype._modifyCommandToDigestPasswordIfNecessary = function(cmdObj, username) {
+ if (!cmdObj["pwd"]) {
+ return;
+ }
+ if (cmdObj.hasOwnProperty("digestPassword")) {
+ throw Error("Cannot specify 'digestPassword' through the user management shell helpers, " +
+ "use 'passwordDigestor' instead");
+ }
+ var passwordDigestor = cmdObj["passwordDigestor"] ? cmdObj["passwordDigestor"] : "server";
+ if (passwordDigestor == "server") {
+ cmdObj["digestPassword"] = true;
+ } else if (passwordDigestor == "client") {
+ cmdObj["pwd"] = _hashPassword(username, cmdObj["pwd"]);
+ cmdObj["digestPassword"] = false;
+ } else {
+ throw Error("'passwordDigestor' must be either 'server' or 'client', got: '" +
+ passwordDigestor + "'");
+ }
+ delete cmdObj["passwordDigestor"];
+};
- DB.prototype.createUser = function(userObj, writeConcern) {
- var name = userObj["user"];
- if (name === undefined) {
- throw Error("no 'user' field provided to 'createUser' function");
- }
+DB.prototype.createUser = function(userObj, writeConcern) {
+ var name = userObj["user"];
+ if (name === undefined) {
+ throw Error("no 'user' field provided to 'createUser' function");
+ }
- if (userObj["createUser"] !== undefined) {
- throw Error("calling 'createUser' function with 'createUser' field is disallowed");
- }
+ if (userObj["createUser"] !== undefined) {
+ throw Error("calling 'createUser' function with 'createUser' field is disallowed");
+ }
- var cmdObj = {createUser: name};
- cmdObj = Object.extend(cmdObj, userObj);
- delete cmdObj["user"];
+ var cmdObj = {createUser: name};
+ cmdObj = Object.extend(cmdObj, userObj);
+ delete cmdObj["user"];
- this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name);
+ this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name);
- cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern;
+ cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern;
- var res = this.runCommand(cmdObj);
+ var res = this.runCommand(cmdObj);
- if (res.ok) {
- print("Successfully added user: " + getUserObjString(userObj));
- return;
- }
+ if (res.ok) {
+ print("Successfully added user: " + getUserObjString(userObj));
+ return;
+ }
- if (res.errmsg == "no such cmd: createUser") {
- throw Error("'createUser' command not found. This is most likely because you are " +
- "talking to an old (pre v2.6) MongoDB server");
- }
+ if (res.errmsg == "no such cmd: createUser") {
+ throw Error("'createUser' command not found. This is most likely because you are " +
+ "talking to an old (pre v2.6) MongoDB server");
+ }
- if (res.errmsg == "timeout") {
- throw Error("timed out while waiting for user authentication to replicate - " +
- "database will not be fully secured until replication finishes");
- }
+ if (res.errmsg == "timeout") {
+ throw Error("timed out while waiting for user authentication to replicate - " +
+ "database will not be fully secured until replication finishes");
+ }
- throw _getErrorWithCode(res, "couldn't add user: " + res.errmsg);
- };
+ throw _getErrorWithCode(res, "couldn't add user: " + res.errmsg);
+};
- function _hashPassword(username, password) {
- if (typeof password != 'string') {
- throw Error("User passwords must be of type string. Was given password with type: " +
- typeof(password));
- }
- return hex_md5(username + ":mongo:" + password);
+function _hashPassword(username, password) {
+ if (typeof password != 'string') {
+ throw Error("User passwords must be of type string. Was given password with type: " +
+ typeof (password));
+ }
+ return hex_md5(username + ":mongo:" + password);
+}
+
+/**
+ * Used for updating users in systems with V1 style user information
+ * (ie MongoDB v2.4 and prior)
+ */
+DB.prototype._updateUserV1 = function(name, updateObject, writeConcern) {
+ var setObj = {};
+ if (updateObject.pwd) {
+ setObj["pwd"] = _hashPassword(name, updateObject.pwd);
+ }
+ if (updateObject.extraData) {
+ setObj["extraData"] = updateObject.extraData;
+ }
+ if (updateObject.roles) {
+ setObj["roles"] = updateObject.roles;
}
- /**
- * Used for updating users in systems with V1 style user information
- * (ie MongoDB v2.4 and prior)
- */
- DB.prototype._updateUserV1 = function(name, updateObject, writeConcern) {
- var setObj = {};
- if (updateObject.pwd) {
- setObj["pwd"] = _hashPassword(name, updateObject.pwd);
- }
- if (updateObject.extraData) {
- setObj["extraData"] = updateObject.extraData;
- }
- if (updateObject.roles) {
- setObj["roles"] = updateObject.roles;
- }
+ this.system.users.update({user: name, userSource: null}, {$set: setObj});
+ var errObj = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']);
+ if (errObj.err) {
+ throw _getErrorWithCode(errObj, "Updating user failed: " + errObj.err);
+ }
+};
- this.system.users.update({user: name, userSource: null}, {$set: setObj});
- var errObj = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']);
- if (errObj.err) {
- throw _getErrorWithCode(errObj, "Updating user failed: " + errObj.err);
- }
- };
+DB.prototype.updateUser = function(name, updateObject, writeConcern) {
+ var cmdObj = {updateUser: name};
+ cmdObj = Object.extend(cmdObj, updateObject);
+ cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern;
+ this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name);
- DB.prototype.updateUser = function(name, updateObject, writeConcern) {
- var cmdObj = {updateUser: name};
- cmdObj = Object.extend(cmdObj, updateObject);
- cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern;
- this._modifyCommandToDigestPasswordIfNecessary(cmdObj, name);
+ var res = this.runCommand(cmdObj);
+ if (res.ok) {
+ return;
+ }
- var res = this.runCommand(cmdObj);
- if (res.ok) {
- return;
- }
+ if (res.errmsg == "no such cmd: updateUser") {
+ this._updateUserV1(name, updateObject, cmdObj['writeConcern']);
+ return;
+ }
- if (res.errmsg == "no such cmd: updateUser") {
- this._updateUserV1(name, updateObject, cmdObj['writeConcern']);
- return;
- }
+ throw _getErrorWithCode(res, "Updating user failed: " + res.errmsg);
+};
- throw _getErrorWithCode(res, "Updating user failed: " + res.errmsg);
- };
+DB.prototype.changeUserPassword = function(username, password, writeConcern) {
+ this.updateUser(username, {pwd: password}, writeConcern);
+};
- DB.prototype.changeUserPassword = function(username, password, writeConcern) {
- this.updateUser(username, {pwd: password}, writeConcern);
- };
+DB.prototype.logout = function() {
+ // Logging out doesn't require a session since it manipulates connection state.
+ return this.getMongo().logout(this.getName());
+};
- DB.prototype.logout = function() {
- // Logging out doesn't require a session since it manipulates connection state.
- return this.getMongo().logout(this.getName());
- };
+// For backwards compatibility
+DB.prototype.removeUser = function(username, writeConcern) {
+ print("WARNING: db.removeUser has been deprecated, please use db.dropUser instead");
+ return this.dropUser(username, writeConcern);
+};
- // For backwards compatibility
- DB.prototype.removeUser = function(username, writeConcern) {
- print("WARNING: db.removeUser has been deprecated, please use db.dropUser instead");
- return this.dropUser(username, writeConcern);
+DB.prototype.dropUser = function(username, writeConcern) {
+ var cmdObj = {
+ dropUser: username,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
- DB.prototype.dropUser = function(username, writeConcern) {
- var cmdObj = {
- dropUser: username,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
-
- if (res.ok) {
- return true;
- }
+ if (res.ok) {
+ return true;
+ }
- if (res.code == 11) { // Code 11 = UserNotFound
- return false;
- }
+ if (res.code == 11) { // Code 11 = UserNotFound
+ return false;
+ }
- if (res.errmsg == "no such cmd: dropUsers") {
- return this._removeUserV1(username, cmdObj['writeConcern']);
- }
+ if (res.errmsg == "no such cmd: dropUsers") {
+ return this._removeUserV1(username, cmdObj['writeConcern']);
+ }
- throw _getErrorWithCode(res, res.errmsg);
- };
+ throw _getErrorWithCode(res, res.errmsg);
+};
- /**
- * Used for removing users in systems with V1 style user information
- * (ie MongoDB v2.4 and prior)
- */
- DB.prototype._removeUserV1 = function(username, writeConcern) {
- this.getCollection("system.users").remove({user: username});
+/**
+ * Used for removing users in systems with V1 style user information
+ * (ie MongoDB v2.4 and prior)
+ */
+DB.prototype._removeUserV1 = function(username, writeConcern) {
+ this.getCollection("system.users").remove({user: username});
- var le = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']);
+ var le = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']);
- if (le.err) {
- throw _getErrorWithCode(le, "Couldn't remove user: " + le.err);
- }
+ if (le.err) {
+ throw _getErrorWithCode(le, "Couldn't remove user: " + le.err);
+ }
- if (le.n == 1) {
- return true;
- } else {
- return false;
- }
- };
+ if (le.n == 1) {
+ return true;
+ } else {
+ return false;
+ }
+};
- DB.prototype.dropAllUsers = function(writeConcern) {
- var res = this.runCommand({
- dropAllUsersFromDatabase: 1,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- });
+DB.prototype.dropAllUsers = function(writeConcern) {
+ var res = this.runCommand({
+ dropAllUsersFromDatabase: 1,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
+ });
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
- return res.n;
- };
+ return res.n;
+};
- DB.prototype.__pwHash = function(nonce, username, pass) {
- return hex_md5(nonce + username + _hashPassword(username, pass));
- };
+DB.prototype.__pwHash = function(nonce, username, pass) {
+ return hex_md5(nonce + username + _hashPassword(username, pass));
+};
- DB.prototype._defaultAuthenticationMechanism = null;
+DB.prototype._defaultAuthenticationMechanism = null;
- DB.prototype._getDefaultAuthenticationMechanism = function(username, database) {
- if (username !== undefined) {
- const userid = database + "." + username;
- const result = this.runCommand({isMaster: 1, saslSupportedMechs: userid});
- if (result.ok && (result.saslSupportedMechs !== undefined)) {
- const mechs = result.saslSupportedMechs;
- if (!Array.isArray(mechs)) {
- throw Error("Server replied with invalid saslSupportedMechs response");
- }
+DB.prototype._getDefaultAuthenticationMechanism = function(username, database) {
+ if (username !== undefined) {
+ const userid = database + "." + username;
+ const result = this.runCommand({isMaster: 1, saslSupportedMechs: userid});
+ if (result.ok && (result.saslSupportedMechs !== undefined)) {
+ const mechs = result.saslSupportedMechs;
+ if (!Array.isArray(mechs)) {
+ throw Error("Server replied with invalid saslSupportedMechs response");
+ }
- if ((this._defaultAuthenticationMechanism != null) &&
- mechs.includes(this._defaultAuthenticationMechanism)) {
- return this._defaultAuthenticationMechanism;
- }
+ if ((this._defaultAuthenticationMechanism != null) &&
+ mechs.includes(this._defaultAuthenticationMechanism)) {
+ return this._defaultAuthenticationMechanism;
+ }
- // Never include PLAIN in auto-negotiation.
- const priority = ["GSSAPI", "SCRAM-SHA-256", "SCRAM-SHA-1"];
- for (var i = 0; i < priority.length; ++i) {
- if (mechs.includes(priority[i])) {
- return priority[i];
- }
+ // Never include PLAIN in auto-negotiation.
+ const priority = ["GSSAPI", "SCRAM-SHA-256", "SCRAM-SHA-1"];
+ for (var i = 0; i < priority.length; ++i) {
+ if (mechs.includes(priority[i])) {
+ return priority[i];
}
}
- // If isMaster doesn't support saslSupportedMechs,
- // or if we couldn't agree on a mechanism,
- // then fallthrough to configured default or SCRAM-SHA-1.
- }
-
- // Use the default auth mechanism if set on the command line.
- if (this._defaultAuthenticationMechanism != null)
- return this._defaultAuthenticationMechanism;
-
- return "SCRAM-SHA-1";
- };
-
- DB.prototype._defaultGssapiServiceName = null;
-
- DB.prototype._authOrThrow = function() {
- var params;
- if (arguments.length == 2) {
- params = {user: arguments[0], pwd: arguments[1]};
- } else if (arguments.length == 1) {
- if (typeof(arguments[0]) != "object")
- throw Error("Single-argument form of auth expects a parameter object");
- params = Object.extend({}, arguments[0]);
- } else {
- throw Error(
- "auth expects either (username, password) or ({ user: username, pwd: password })");
- }
-
- if (params.mechanism === undefined) {
- params.mechanism = this._getDefaultAuthenticationMechanism(params.user, this.getName());
- }
-
- if (params.db !== undefined) {
- throw Error("Do not override db field on db.auth(). Use getMongo().auth(), instead.");
}
+ // If isMaster doesn't support saslSupportedMechs,
+ // or if we couldn't agree on a mechanism,
+ // then fallthrough to configured default or SCRAM-SHA-1.
+ }
- if (params.mechanism == "GSSAPI" && params.serviceName == null &&
- this._defaultGssapiServiceName != null) {
- params.serviceName = this._defaultGssapiServiceName;
- }
-
- // Logging in doesn't require a session since it manipulates connection state.
- params.db = this.getName();
- var good = this.getMongo().auth(params);
- if (good) {
- // auth enabled, and should try to use isMaster and replSetGetStatus to build prompt
- this.getMongo().authStatus = {
- authRequired: true,
- isMaster: true,
- replSetGetStatus: true
- };
- }
-
- return good;
- };
-
- DB.prototype.auth = function() {
- var ex;
- try {
- this._authOrThrow.apply(this, arguments);
- } catch (ex) {
- print(ex);
- return 0;
- }
- return 1;
- };
-
- DB.prototype.grantRolesToUser = function(username, roles, writeConcern) {
- var cmdObj = {
- grantRolesToUser: username,
- roles: roles,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+ // Use the default auth mechanism if set on the command line.
+ if (this._defaultAuthenticationMechanism != null)
+ return this._defaultAuthenticationMechanism;
+
+ return "SCRAM-SHA-1";
+};
+
+DB.prototype._defaultGssapiServiceName = null;
+
+DB.prototype._authOrThrow = function() {
+ var params;
+ if (arguments.length == 2) {
+ params = {user: arguments[0], pwd: arguments[1]};
+ } else if (arguments.length == 1) {
+ if (typeof (arguments[0]) != "object")
+ throw Error("Single-argument form of auth expects a parameter object");
+ params = Object.extend({}, arguments[0]);
+ } else {
+ throw Error(
+ "auth expects either (username, password) or ({ user: username, pwd: password })");
+ }
- DB.prototype.revokeRolesFromUser = function(username, roles, writeConcern) {
- var cmdObj = {
- revokeRolesFromUser: username,
- roles: roles,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+ if (params.mechanism === undefined) {
+ params.mechanism = this._getDefaultAuthenticationMechanism(params.user, this.getName());
+ }
- DB.prototype.getUser = function(username, args) {
- if (typeof username != "string") {
- throw Error("User name for getUser shell helper must be a string");
- }
- var cmdObj = {usersInfo: username};
- Object.extend(cmdObj, args);
+ if (params.db !== undefined) {
+ throw Error("Do not override db field on db.auth(). Use getMongo().auth(), instead.");
+ }
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
+ if (params.mechanism == "GSSAPI" && params.serviceName == null &&
+ this._defaultGssapiServiceName != null) {
+ params.serviceName = this._defaultGssapiServiceName;
+ }
- if (res.users.length == 0) {
- return null;
- }
- return res.users[0];
- };
+ // Logging in doesn't require a session since it manipulates connection state.
+ params.db = this.getName();
+ var good = this.getMongo().auth(params);
+ if (good) {
+ // auth enabled, and should try to use isMaster and replSetGetStatus to build prompt
+ this.getMongo().authStatus = {authRequired: true, isMaster: true, replSetGetStatus: true};
+ }
- DB.prototype.getUsers = function(args) {
- var cmdObj = {usersInfo: 1};
- Object.extend(cmdObj, args);
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- var authSchemaIncompatibleCode = 69;
- if (res.code == authSchemaIncompatibleCode ||
- (res.code == null && res.errmsg == "no such cmd: usersInfo")) {
- // Working with 2.4 schema user data
- return this.system.users.find({}).toArray();
- }
+ return good;
+};
- throw _getErrorWithCode(res, res.errmsg);
- }
+DB.prototype.auth = function() {
+ var ex;
+ try {
+ this._authOrThrow.apply(this, arguments);
+ } catch (ex) {
+ print(ex);
+ return 0;
+ }
+ return 1;
+};
- return res.users;
+DB.prototype.grantRolesToUser = function(username, roles, writeConcern) {
+ var cmdObj = {
+ grantRolesToUser: username,
+ roles: roles,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.createRole = function(roleObj, writeConcern) {
- var name = roleObj["role"];
- var cmdObj = {createRole: name};
- cmdObj = Object.extend(cmdObj, roleObj);
- delete cmdObj["role"];
- cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern;
-
- var res = this.runCommand(cmdObj);
-
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- printjson(roleObj);
+DB.prototype.revokeRolesFromUser = function(username, roles, writeConcern) {
+ var cmdObj = {
+ revokeRolesFromUser: username,
+ roles: roles,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.updateRole = function(name, updateObject, writeConcern) {
- var cmdObj = {updateRole: name};
- cmdObj = Object.extend(cmdObj, updateObject);
- cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern;
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+DB.prototype.getUser = function(username, args) {
+ if (typeof username != "string") {
+ throw Error("User name for getUser shell helper must be a string");
+ }
+ var cmdObj = {usersInfo: username};
+ Object.extend(cmdObj, args);
- DB.prototype.dropRole = function(name, writeConcern) {
- var cmdObj = {
- dropRole: name,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
- if (res.ok) {
- return true;
- }
+ if (res.users.length == 0) {
+ return null;
+ }
+ return res.users[0];
+};
- if (res.code == 31) { // Code 31 = RoleNotFound
- return false;
+DB.prototype.getUsers = function(args) {
+ var cmdObj = {usersInfo: 1};
+ Object.extend(cmdObj, args);
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ var authSchemaIncompatibleCode = 69;
+ if (res.code == authSchemaIncompatibleCode ||
+ (res.code == null && res.errmsg == "no such cmd: usersInfo")) {
+ // Working with 2.4 schema user data
+ return this.system.users.find({}).toArray();
}
throw _getErrorWithCode(res, res.errmsg);
- };
-
- DB.prototype.dropAllRoles = function(writeConcern) {
- var res = this.runCommand({
- dropAllRolesFromDatabase: 1,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- });
-
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
+ }
- return res.n;
- };
+ return res.users;
+};
- DB.prototype.grantRolesToRole = function(rolename, roles, writeConcern) {
- var cmdObj = {
- grantRolesToRole: rolename,
- roles: roles,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+DB.prototype.createRole = function(roleObj, writeConcern) {
+ var name = roleObj["role"];
+ var cmdObj = {createRole: name};
+ cmdObj = Object.extend(cmdObj, roleObj);
+ delete cmdObj["role"];
+ cmdObj["writeConcern"] = writeConcern ? writeConcern : _defaultWriteConcern;
- DB.prototype.revokeRolesFromRole = function(rolename, roles, writeConcern) {
- var cmdObj = {
- revokeRolesFromRole: rolename,
- roles: roles,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+ var res = this.runCommand(cmdObj);
- DB.prototype.grantPrivilegesToRole = function(rolename, privileges, writeConcern) {
- var cmdObj = {
- grantPrivilegesToRole: rolename,
- privileges: privileges,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+ printjson(roleObj);
+};
+
+DB.prototype.updateRole = function(name, updateObject, writeConcern) {
+ var cmdObj = {updateRole: name};
+ cmdObj = Object.extend(cmdObj, updateObject);
+ cmdObj['writeConcern'] = writeConcern ? writeConcern : _defaultWriteConcern;
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.revokePrivilegesFromRole = function(rolename, privileges, writeConcern) {
- var cmdObj = {
- revokePrivilegesFromRole: rolename,
- privileges: privileges,
- writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
- };
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
- };
+DB.prototype.dropRole = function(name, writeConcern) {
+ var cmdObj = {dropRole: name, writeConcern: writeConcern ? writeConcern : _defaultWriteConcern};
+ var res = this.runCommand(cmdObj);
- DB.prototype.getRole = function(rolename, args) {
- if (typeof rolename != "string") {
- throw Error("Role name for getRole shell helper must be a string");
- }
- var cmdObj = {rolesInfo: rolename};
- Object.extend(cmdObj, args);
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
+ if (res.ok) {
+ return true;
+ }
- if (res.roles.length == 0) {
- return null;
- }
- return res.roles[0];
- };
+ if (res.code == 31) { // Code 31 = RoleNotFound
+ return false;
+ }
- DB.prototype.getRoles = function(args) {
- var cmdObj = {rolesInfo: 1};
- Object.extend(cmdObj, args);
- var res = this.runCommand(cmdObj);
- if (!res.ok) {
- throw _getErrorWithCode(res, res.errmsg);
- }
+ throw _getErrorWithCode(res, res.errmsg);
+};
- return res.roles;
- };
+DB.prototype.dropAllRoles = function(writeConcern) {
+ var res = this.runCommand({
+ dropAllRolesFromDatabase: 1,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
+ });
- DB.prototype.setWriteConcern = function(wc) {
- if (wc instanceof WriteConcern) {
- this._writeConcern = wc;
- } else {
- this._writeConcern = new WriteConcern(wc);
- }
- };
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
- DB.prototype.getWriteConcern = function() {
- if (this._writeConcern)
- return this._writeConcern;
+ return res.n;
+};
- {
- const session = this.getSession();
- return session._getSessionAwareClient().getWriteConcern(session);
- }
+DB.prototype.grantRolesToRole = function(rolename, roles, writeConcern) {
+ var cmdObj = {
+ grantRolesToRole: rolename,
+ roles: roles,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.unsetWriteConcern = function() {
- delete this._writeConcern;
+DB.prototype.revokeRolesFromRole = function(rolename, roles, writeConcern) {
+ var cmdObj = {
+ revokeRolesFromRole: rolename,
+ roles: roles,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.getLogComponents = function() {
- return this.getMongo().getLogComponents(this.getSession());
+DB.prototype.grantPrivilegesToRole = function(rolename, privileges, writeConcern) {
+ var cmdObj = {
+ grantPrivilegesToRole: rolename,
+ privileges: privileges,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.setLogLevel = function(logLevel, component) {
- return this.getMongo().setLogLevel(logLevel, component, this.getSession());
+DB.prototype.revokePrivilegesFromRole = function(rolename, privileges, writeConcern) {
+ var cmdObj = {
+ revokePrivilegesFromRole: rolename,
+ privileges: privileges,
+ writeConcern: writeConcern ? writeConcern : _defaultWriteConcern
};
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
+};
- DB.prototype.watch = function(pipeline, options) {
- pipeline = pipeline || [];
- assert(pipeline instanceof Array, "'pipeline' argument must be an array");
-
- let changeStreamStage;
- [changeStreamStage, aggOptions] = this.getMongo()._extractChangeStreamOptions(options);
- pipeline.unshift(changeStreamStage);
- return this._runAggregate({aggregate: 1, pipeline: pipeline}, aggOptions);
- };
+DB.prototype.getRole = function(rolename, args) {
+ if (typeof rolename != "string") {
+ throw Error("Role name for getRole shell helper must be a string");
+ }
+ var cmdObj = {rolesInfo: rolename};
+ Object.extend(cmdObj, args);
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
- DB.prototype.getFreeMonitoringStatus = function() {
- 'use strict';
- return assert.commandWorked(this.adminCommand({getFreeMonitoringStatus: 1}));
- };
+ if (res.roles.length == 0) {
+ return null;
+ }
+ return res.roles[0];
+};
+
+DB.prototype.getRoles = function(args) {
+ var cmdObj = {rolesInfo: 1};
+ Object.extend(cmdObj, args);
+ var res = this.runCommand(cmdObj);
+ if (!res.ok) {
+ throw _getErrorWithCode(res, res.errmsg);
+ }
- DB.prototype.enableFreeMonitoring = function() {
- 'use strict';
- const isMaster = this.isMaster();
- if (isMaster.ismaster == false) {
- print("ERROR: db.enableFreeMonitoring() may only be run on a primary");
- return;
- }
+ return res.roles;
+};
- assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'enable'}));
+DB.prototype.setWriteConcern = function(wc) {
+ if (wc instanceof WriteConcern) {
+ this._writeConcern = wc;
+ } else {
+ this._writeConcern = new WriteConcern(wc);
+ }
+};
- const cmd = this.adminCommand({getFreeMonitoringStatus: 1});
- if (!cmd.ok && (cmd.code == ErrorCode.Unauthorized)) {
- // Edge case: It's technically possible that a user can change free-mon state,
- // but is not allowed to inspect it.
- print("Successfully initiated free monitoring, but unable to determine status " +
- "as you lack the 'checkFreeMonitoringStatus' privilege.");
- return;
- }
- assert.commandWorked(cmd);
+DB.prototype.getWriteConcern = function() {
+ if (this._writeConcern)
+ return this._writeConcern;
- if (cmd.state !== 'enabled') {
- const url = this.adminCommand({'getParameter': 1, 'cloudFreeMonitoringEndpointURL': 1})
- .cloudFreeMonitoringEndpointURL;
+ {
+ const session = this.getSession();
+ return session._getSessionAwareClient().getWriteConcern(session);
+ }
+};
+
+DB.prototype.unsetWriteConcern = function() {
+ delete this._writeConcern;
+};
+
+DB.prototype.getLogComponents = function() {
+ return this.getMongo().getLogComponents(this.getSession());
+};
+
+DB.prototype.setLogLevel = function(logLevel, component) {
+ return this.getMongo().setLogLevel(logLevel, component, this.getSession());
+};
+
+DB.prototype.watch = function(pipeline, options) {
+ pipeline = pipeline || [];
+ assert(pipeline instanceof Array, "'pipeline' argument must be an array");
+
+ let changeStreamStage;
+ [changeStreamStage, aggOptions] = this.getMongo()._extractChangeStreamOptions(options);
+ pipeline.unshift(changeStreamStage);
+ return this._runAggregate({aggregate: 1, pipeline: pipeline}, aggOptions);
+};
+
+DB.prototype.getFreeMonitoringStatus = function() {
+ 'use strict';
+ return assert.commandWorked(this.adminCommand({getFreeMonitoringStatus: 1}));
+};
+
+DB.prototype.enableFreeMonitoring = function() {
+ 'use strict';
+ const isMaster = this.isMaster();
+ if (isMaster.ismaster == false) {
+ print("ERROR: db.enableFreeMonitoring() may only be run on a primary");
+ return;
+ }
- print("Unable to get immediate response from the Cloud Monitoring service. We will" +
- "continue to retry in the background. Please check your firewall " +
- "settings to ensure that mongod can communicate with \"" + url + "\"");
- return;
- }
+ assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'enable'}));
- print(tojson(cmd));
- };
+ const cmd = this.adminCommand({getFreeMonitoringStatus: 1});
+ if (!cmd.ok && (cmd.code == ErrorCode.Unauthorized)) {
+ // Edge case: It's technically possible that a user can change free-mon state,
+ // but is not allowed to inspect it.
+ print("Successfully initiated free monitoring, but unable to determine status " +
+ "as you lack the 'checkFreeMonitoringStatus' privilege.");
+ return;
+ }
+ assert.commandWorked(cmd);
- DB.prototype.disableFreeMonitoring = function() {
- 'use strict';
- assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'disable'}));
- };
+ if (cmd.state !== 'enabled') {
+ const url = this.adminCommand({'getParameter': 1, 'cloudFreeMonitoringEndpointURL': 1})
+ .cloudFreeMonitoringEndpointURL;
- // Writing `this.hasOwnProperty` would cause DB.prototype.getCollection() to be called since the
- // DB's getProperty() handler in C++ takes precedence when a property isn't defined on the DB
- // instance directly. The "hasOwnProperty" property is defined on Object.prototype, so we must
- // resort to using the function explicitly ourselves.
- (function(hasOwnProperty) {
- DB.prototype.getSession = function() {
- if (!hasOwnProperty.call(this, "_session")) {
- this._session = this.getMongo()._getDefaultSession();
- }
- return this._session;
- };
- })(Object.prototype.hasOwnProperty);
+ print("Unable to get immediate response from the Cloud Monitoring service. We will" +
+ "continue to retry in the background. Please check your firewall " +
+ "settings to ensure that mongod can communicate with \"" + url + "\"");
+ return;
+ }
+ print(tojson(cmd));
+};
+
+DB.prototype.disableFreeMonitoring = function() {
+ 'use strict';
+ assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'disable'}));
+};
+
+// Writing `this.hasOwnProperty` would cause DB.prototype.getCollection() to be called since the
+// DB's getProperty() handler in C++ takes precedence when a property isn't defined on the DB
+// instance directly. The "hasOwnProperty" property is defined on Object.prototype, so we must
+// resort to using the function explicitly ourselves.
+(function(hasOwnProperty) {
+DB.prototype.getSession = function() {
+ if (!hasOwnProperty.call(this, "_session")) {
+ this._session = this.getMongo()._getDefaultSession();
+ }
+ return this._session;
+};
+})(Object.prototype.hasOwnProperty);
}());