Thanks, Chris.
Maybe I find out the root cause.
I’m trying to use this command to save data. Then got the same result, but find the result did not output the [Object]. Look at the following commands.
test:PRIMARY> db.test_h.insert(db)
test:PRIMARY> db.test_h.find()
{ "_id" : ObjectId("640e944beca0dd84c5bc153a"), "_mongo" : { "slaveOk" : false, "host" : "127.0.0.1:27017", "defaultDB" : "admin", "_defaultSession" : [Object], "_causalConsistency" : false, "_clusterTime" : { "clusterTime" : Timestamp(1678677059, 57), "signature" : { "hash" : BinData(0,"5kBzUeXFPank5uJ2eTrtcu+kmJE="), "keyId" : NumberLong("7171362007151542467") } }, "_readMode" : "commands", "promptPrefix" : "", "authStatus" : { "replSetGetStatus" : true, "isMaster" : true }, "_writeMode" : "commands" }, "_name" : "opc_dft", "_session" : [Object], "_attachReadPreferenceToCommand" : { "code" : "function(cmdObj, readPref) {\n \"use strict\";\n // if the user has not set a readpref, return the original cmdObj\n if ((readPref === null) || typeof (readPref) !== \"object\") {\n return cmdObj;\n }\n\n // if user specifies $readPreference manually, then don't change it\n if (cmdObj.hasOwnProperty(\"$readPreference\")) {\n return cmdObj;\n }\n\n // copy object so we don't mutate the original\n var clonedCmdObj = Object.extend({}, cmdObj);\n // The server selection spec mandates that the key is '$query', but\n // the shell has historically used 'query'. The server accepts both,\n // so we maintain the existing behavior\n var cmdObjWithReadPref = {query: clonedCmdObj, $readPreference: readPref};\n return cmdObjWithReadPref;\n}" }, "_mergeCommandOptions" : { "code" : "function(obj, extraKeys) {\n \"use strict\";\n\n if (typeof (obj) === \"object\") {\n if (Object.keys(extraKeys || {}).length > 0) {\n throw Error(\"Unexpected second argument to DB.runCommand(): (type: \" +\n typeof (extraKeys) + \"): \" + tojson(extraKeys));\n }\n return obj;\n } else if (typeof (obj) !== \"string\") {\n throw Error(\"First argument to DB.runCommand() must be either an object or a string: \" +\n \"(type: \" + typeof (obj) + \"): \" + tojson(obj));\n }\n\n var commandName = obj;\n var mergedCmdObj = {};\n mergedCmdObj[commandName] = 1;\n\n if (!extraKeys) {\n return mergedCmdObj;\n } else if (typeof (extraKeys) === \"object\") {\n // this will traverse the prototype chain of extra, but keeping\n // to maintain legacy behavior\n for (var key in extraKeys) {\n mergedCmdObj[key] = extraKeys[key];\n }\n } else {\n throw Error(\"Second argument to DB.runCommand(\" + commandName +\n \") must be an object: (type: \" + typeof (extraKeys) +\n \"): \" + tojson(extraKeys));\n }\n\n return mergedCmdObj;\n}" }, "_runCommandImpl" : { "code" : "function(name, obj, options) {\n const session = this.getSession();\n return session._getSessionAwareClient().runCommand(session, name, obj, options);\n}" }, "_dbCommand" : { "code" : "function(obj, extra, queryOptions) {\n \"use strict\";\n\n // Support users who call this function with a string commandName, e.g.\n // db.runCommand(\"commandName\", {arg1: \"value\", arg2: \"value\"}).\n var mergedObj = this._mergeCommandOptions(obj, extra);\n\n // if options were passed (i.e. because they were overridden on a collection), use them.\n // Otherwise use getQueryOptions.\n var options = (typeof (queryOptions) !== \"undefined\") ? queryOptions : this.getQueryOptions();\n\n try {\n return this._runCommandImpl(this._name, mergedObj, options);\n } catch (ex) {\n // When runCommand flowed through query, a connection error resulted in the message\n // \"error doing query: failed\". Even though this message is arguably incorrect\n // for a command failing due to a connection failure, we preserve it for backwards\n // compatibility. See SERVER-18334 for details.\n if (ex.message.indexOf(\"network error\") >= 0) {\n throw new Error(\"error doing query: failed: \" + ex.message);\n }\n throw ex;\n }\n}" }, "_dbReadCommand" : { "code" : "function(obj, extra, queryOptions) {\n \"use strict\";\n\n // Support users who call this function with a string commandName, e.g.\n // db.runReadCommand(\"commandName\", {arg1: \"value\", arg2: \"value\"}).\n obj = this._mergeCommandOptions(obj, extra);\n queryOptions = queryOptions !== undefined ? queryOptions : this.getQueryOptions();\n\n {\n const session = this.getSession();\n\n const readPreference = session._getSessionAwareClient().getReadPreference(session);\n if (readPreference !== null) {\n obj = this._attachReadPreferenceToCommand(obj, readPreference);\n\n if (readPreference.mode !== \"primary\") {\n // Set slaveOk if readPrefMode has been explicitly set with a readPreference\n // other than primary.\n queryOptions |= 4;\n }\n }\n }\n\n // The 'extra' parameter is not used as we have already created a merged command object.\n return this.runCommand(obj, null, queryOptions);\n}" }, "_adminCommand" : { "code" : "function(obj, extra) {\n if (this._name == \"admin\")\n return this.runCommand(obj, extra);\n return this.getSiblingDB(\"admin\").runCommand(obj, extra);\n}" }, "_runAggregate" : { "code" : "function(cmdObj, aggregateOptions) {\n assert(cmdObj.pipeline instanceof Array, \"cmdObj must contain a 'pipeline' array\");\n assert(cmdObj.aggregate !== undefined, \"cmdObj must contain 'aggregate' field\");\n assert(aggregateOptions === undefined || aggregateOptions instanceof Object,\n \"'aggregateOptions' argument must be an object\");\n\n // Make a copy of the initial command object, i.e. {aggregate: x, pipeline: [...]}.\n cmdObj = Object.extend({}, cmdObj);\n\n // Make a copy of the aggregation options.\n let optcpy = Object.extend({}, (aggregateOptions || {}));\n\n if ('batchSize' in optcpy) {\n if (optcpy.cursor == null) {\n optcpy.cursor = {};\n }\n\n optcpy.cursor.batchSize = optcpy['batchSize'];\n delete optcpy['batchSize'];\n } else if ('useCursor' in optcpy) {\n if (optcpy.cursor == null) {\n optcpy.cursor = {};\n }\n\n delete optcpy['useCursor'];\n }\n\n const maxAwaitTimeMS = optcpy.maxAwaitTimeMS;\n delete optcpy.maxAwaitTimeMS;\n\n // Reassign the cleaned-up options.\n aggregateOptions = optcpy;\n\n // Add the options to the command object.\n Object.extend(cmdObj, aggregateOptions);\n\n if (!('cursor' in cmdObj)) {\n cmdObj.cursor = {};\n }\n\n const pipeline = cmdObj.pipeline;\n\n // Check whether the pipeline has a stage which performs writes like $out. If not, we may\n // run on a Secondary and should attach a readPreference.\n const hasWritingStage = (function() {\n if (pipeline.length == 0) {\n return false;\n }\n const lastStage = pipeline[pipeline.length - 1];\n return lastStage.hasOwnProperty(\"$out\") || lastStage.hasOwnProperty(\"$merge\");\n }());\n\n const doAgg = function(cmdObj) {\n return hasWritingStage ? this.runCommand(cmdObj) : this.runReadCommand(cmdObj);\n }.bind(this);\n\n const res = doAgg(cmdObj);\n\n if (!res.ok && (res.code == 17020 || res.errmsg == \"unrecognized field \\\"cursor\") &&\n !(\"cursor\" in aggregateOptions)) {\n // If the command failed because cursors aren't supported and the user didn't explicitly\n // request a cursor, try again without requesting a cursor.\n delete cmdObj.cursor;\n\n res = doAgg(cmdObj);\n\n if ('result' in res && !(\"cursor\" in res)) {\n // convert old-style output to cursor-style output\n res.cursor = {ns: '', id: NumberLong(0)};\n res.cursor.firstBatch = res.result;\n delete res.result;\n }\n }\n\n assert.commandWorked(res, \"aggregate failed\");\n\n if (\"cursor\" in res) {\n let batchSizeValue = undefined;\n\n if (cmdObj[\"cursor\"][\"batchSize\"] > 0) {\n batchSizeValue = cmdObj[\"cursor\"][\"batchSize\"];\n }\n\n return new DBCommandCursor(this, res, batchSizeValue, maxAwaitTimeMS);\n }\n\n return res;\n}" }, "_groupFixParms" : { "code" : "function(parmsObj) {\n var parms = Object.extend({}, parmsObj);\n\n if (parms.reduce) {\n parms.$reduce = parms.reduce; // must have $ to pass to db\n delete parms.reduce;\n }\n\n if (parms.keyf) {\n parms.$keyf = parms.keyf;\n delete parms.keyf;\n }\n\n return parms;\n}" }, "_getCollectionInfosCommand" : { "code" : "function(\n filter, nameOnly = false, authorizedCollections = false, options = {}) {\n filter = filter || {};\n const cmd = {\n listCollections: 1,\n filter: filter,\n nameOnly: nameOnly,\n authorizedCollections: authorizedCollections\n };\n\n const res = this.runCommand(Object.merge(cmd, options));\n if (!res.ok) {\n throw _getErrorWithCode(res, \"listCollections failed: \" + tojson(res));\n }\n\n return new DBCommandCursor(this, res).toArray().sort(compareOn(\"name\"));\n}" }, "_getCollectionInfosFromPrivileges" : { "code" : "function() {\n let ret = this.runCommand({connectionStatus: 1, showPrivileges: 1});\n if (!ret.ok) {\n throw _getErrorWithCode(res, \"Failed to acquire collection information from privileges\");\n }\n\n // Parse apart collection information.\n let result = [];\n\n let privileges = ret.authInfo.authenticatedUserPrivileges;\n if (privileges === undefined) {\n return result;\n }\n\n privileges.forEach(privilege => {\n let resource = privilege.resource;\n if (resource === undefined) {\n return;\n }\n let db = resource.db;\n if (db === undefined || db !== this.getName()) {\n return;\n }\n let collection = resource.collection;\n if (collection === undefined || typeof collection !== \"string\" || collection === \"\") {\n return;\n }\n\n result.push({name: collection});\n });\n\n return result.sort(compareOn(\"name\"));\n}" }, "_getCollectionNamesInternal" : { "code" : "function(options) {\n return this._getCollectionInfosCommand({}, true, true, options).map(function(infoObj) {\n return infoObj.name;\n });\n}" }, "_modifyCommandToDigestPasswordIfNecessary" : { "code" : "function(cmdObj, username) {\n if (!cmdObj[\"pwd\"]) {\n return;\n }\n if (cmdObj.hasOwnProperty(\"digestPassword\")) {\n throw Error(\"Cannot specify 'digestPassword' through the user management shell helpers, \" +\n \"use 'passwordDigestor' instead\");\n }\n var passwordDigestor = cmdObj[\"passwordDigestor\"] ? cmdObj[\"passwordDigestor\"] : \"server\";\n if (passwordDigestor == \"server\") {\n cmdObj[\"digestPassword\"] = true;\n } else if (passwordDigestor == \"client\") {\n cmdObj[\"pwd\"] = _hashPassword(username, cmdObj[\"pwd\"]);\n cmdObj[\"digestPassword\"] = false;\n } else {\n throw Error(\"'passwordDigestor' must be either 'server' or 'client', got: '\" +\n passwordDigestor + \"'\");\n }\n delete cmdObj[\"passwordDigestor\"];\n}" }, "_updateUserV1" : { "code" : "function(name, updateObject, writeConcern) {\n var setObj = {};\n if (updateObject.pwd) {\n setObj[\"pwd\"] = _hashPassword(name, updateObject.pwd);\n }\n if (updateObject.extraData) {\n setObj[\"extraData\"] = updateObject.extraData;\n }\n if (updateObject.roles) {\n setObj[\"roles\"] = updateObject.roles;\n }\n\n this.system.users.update({user: name, userSource: null}, {$set: setObj});\n var errObj = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']);\n if (errObj.err) {\n throw _getErrorWithCode(errObj, \"Updating user failed: \" + errObj.err);\n }\n}" }, "_removeUserV1" : { "code" : "function(username, writeConcern) {\n this.getCollection(\"system.users\").remove({user: username});\n\n var le = this.getLastErrorObj(writeConcern['w'], writeConcern['wtimeout']);\n\n if (le.err) {\n throw _getErrorWithCode(le, \"Couldn't remove user: \" + le.err);\n }\n\n if (le.n == 1) {\n return true;\n } else {\n return false;\n }\n}" }, "__pwHash" : { "code" : "function(nonce, username, pass) {\n return hex_md5(nonce + username + _hashPassword(username, pass));\n}" }, "_defaultAuthenticationMechanism" : null, "_getDefaultAuthenticationMechanism" : { "code" : "function(username, database) {\n if (username !== undefined) {\n const userid = database + \".\" + username;\n const result = this.runCommand({isMaster: 1, saslSupportedMechs: userid});\n if (result.ok && (result.saslSupportedMechs !== undefined)) {\n const mechs = result.saslSupportedMechs;\n if (!Array.isArray(mechs)) {\n throw Error(\"Server replied with invalid saslSupportedMechs response\");\n }\n\n if ((this._defaultAuthenticationMechanism != null) &&\n mechs.includes(this._defaultAuthenticationMechanism)) {\n return this._defaultAuthenticationMechanism;\n }\n\n // Never include PLAIN in auto-negotiation.\n const priority = [\"GSSAPI\", \"SCRAM-SHA-256\", \"SCRAM-SHA-1\"];\n for (var i = 0; i < priority.length; ++i) {\n if (mechs.includes(priority[i])) {\n return priority[i];\n }\n }\n }\n // If isMaster doesn't support saslSupportedMechs,\n // or if we couldn't agree on a mechanism,\n // then fallthrough to configured default or SCRAM-SHA-1.\n }\n\n // Use the default auth mechanism if set on the command line.\n if (this._defaultAuthenticationMechanism != null)\n return this._defaultAuthenticationMechanism;\n\n return \"SCRAM-SHA-1\";\n}" }, "_defaultGssapiServiceName" : "mongodb", "_authOrThrow" : { "code" : "function() {\n var params;\n if (arguments.length == 2) {\n params = {user: arguments[0], pwd: arguments[1]};\n } else if (arguments.length == 1) {\n if (typeof (arguments[0]) != \"object\")\n throw Error(\"Single-argument form of auth expects a parameter object\");\n params = Object.extend({}, arguments[0]);\n } else {\n throw Error(\n \"auth expects either (username, password) or ({ user: username, pwd: password })\");\n }\n\n if (params.mechanism === undefined) {\n params.mechanism = this._getDefaultAuthenticationMechanism(params.user, this.getName());\n }\n\n if (params.db !== undefined) {\n throw Error(\"Do not override db field on db.auth(). Use getMongo().auth(), instead.\");\n }\n\n if (params.mechanism == \"GSSAPI\" && params.serviceName == null &&\n this._defaultGssapiServiceName != null) {\n params.serviceName = this._defaultGssapiServiceName;\n }\n\n // Logging in doesn't require a session since it manipulates connection state.\n params.db = this.getName();\n var good = this.getMongo().auth(params);\n if (good) {\n // auth enabled, and should try to use isMaster and replSetGetStatus to build prompt\n this.getMongo().authStatus = {authRequired: true, isMaster: true, replSetGetStatus: true};\n }\n\n return good;\n}" } }
There is another puzzle. Why the find command output is json format not the [Object]? Thanks