Using the MongoDB Shell

I believe it was Albert Einstein who said “Any man who reads too much and uses his own brain too little falls into lazy habits of thinking”. I like to read in order to learn about different subjects, mostly associated with computer science and technology. I also like to experiment with what I am reading in order to verify that I understand the material.Earlier this year I bought a copy of “MongoDB – The Definitive Guide” by Kristina Chodorow published by O’Reilly. The reason is that I am starting to use MongoDB for different projects. A couple years ago I read and experimented with Cassandra, but decided to go with MongoDB.

MongoDB comes with a shell which is used to interact with the NoSQL document database. The shell understands JavaScript. JavaScript is used extensively to interact with MongoDB. I decided to spend some time experimenting with examples illustrated in the book. Of course the idea is not just to copy and paste but to experiment with the base examples. This post covers some experimentation using the shell on a Windows 10 computer in which I have installed MongoDB.

MongoDB comes with a graphical tool called Compass. Compass is great for some basic operations. Like in Linux and Windows, if you want to have access to most commands, then you need to switch from the UI to a console based tool.

On a side note, I started editing this post yesterday morning around 08:00 AM. As I have mentioned on several posts I am a morning person. I get up no later than 05:30 AM. Yesterday was no exception. I also work and study in blocks of two hours. Yesterday I was started my Windows computer around 06:45 AM. Like to work / study in two hour blocks. Sitting all day without interruptions is no good for our body. There are many studies on the web performed by accredited researches and institutions.

So it was around 08:20 AM and a notification popped up. It was letting me know that I had a Windows update which would require restarting the machine. I decided to close all the windows I had opened and restart my machine. So I did. I then went to the kitchen, heated some water in the microwave (we had our kitchen remodeled a couple months ago and among other things, we had installed an additional faucet with very hot water). My wife uses the hot water for her coffee. For some reason I still like to heat the water in the microwave. I also walk around and chat for a few minutes with my wife.

My breaks last no more than 10 minutes. So around 08:30 I got back to my computer. The update was in progress and had performed about 2% of what it had to do. I went back and continued to walk and chat with my wife for another 10 minutes. When I got back to the computer progress was about 5%.

We were planning to go to the St. Paul Farmers Market and we had purchased a Whitmor Deluxe Utility Cart – Durable Folding Design for Easy Storage cart from Amazon which had already been delivered. I decided to put it together. Got tools, opened the box. Laid out all the parts next to the instructions and noticed that a cotter pin was missing. The instructions called out for two and I only received one.

I looked around the garage for a cotter pin. Decided to cut a thin nail and use it as a pin. That would be faster than going to the hardware store. As I was putting together the cart, I was thinking that Windows update would be done any time. Forty five minutes go by and I was done. I invited my wife to the garage to see my masterpiece in action. The task was completed so I folded the cart and decided to put it into the trunk of our B6 Alpina. The boot would not close. The cart was a quarter of an inch too long.

I mentioned to my wife that we could always use a second cart around the house so I could order a smaller one from Amazon. She reminded me that her new SUV will be delivered in less than a month. We have been going to the Farmer’s Market for years and we had always carried the veggies in bags. An additional trip or two would not kill us.

After cleaning up, went to my computer. It had completed about 40% of the update. My wife was baking a cake and had to visit a neighbor. She needed help decorating some things at home. My wife left and I sat with the MongoDB book smelling the chocolate cake as it was baking. After 45 minutes my wife came back and pulled the cake out of the oven. The Windows update was still going on. It had about 25% to go.

We decided to go for our walk. On weekends we walk a few miles per day. The length is based on weather conditions.  Yesterday it was rather cold and looked like it could start raining at any time. We decided on a short mile and a half walk.

When we got back it was around 11:00 AM and the update had 15% to go. We decided to drive to the ST. Paul Farmer’s Market. We got some asparagus and beets. Not much of a selection yet. We found lots of flowers and herbs to plant at the market but not many veggies to fix salads with.

When we arrived home the update had completed and my machine was off. Started and all seemed to be back to normal. The update took about 4 hours to complete. We had to go to a late lunch appointment so my wife frosted the cake and we headed out.

This morning I was in front of the computer before 07:00 AM. I decided to edit into this post my Windows update experience. If you have not received the update yet, make sure you leave it to get done overnight.

OK meanwhile, back at the ranch…

There are different ways to start the MongoDB shell. Note that by default it attempts to connect to the local MongoDB server. It can be used to connect to a remote instance or not connect at all.

The following screen capture shows what happens when connecting to my local MongoDB instance. From a command prompt:

C:\Temp\MongoDB>mongo
MongoDB shell version v3.6.4
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.4
Server has startup warnings:
2018-05-20T07:50:13.922-0500 I CONTROL  [initandlisten]
2018-05-20T07:50:13.922-0500 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-05-20T07:50:13.922-0500 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten]
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] ** WARNING: This server is bound to localhost.
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server.
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] **          Start the server with --bind_ip <address> to specify which IP
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] **          addresses it should serve responses from, or with --bind_ip_all to
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] **          bind to all interfaces. If this behavior is desired, start the
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] **          server with --bind_ip 127.0.0.1 to disable this warning.
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten]
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten]
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] ** WARNING: The file system cache of this machine is configured to be greater than 40% of the total memory. This can
 lead to increased memory pressure and poor performance.
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten] See http://dochub.mongodb.org/core/wt-windows-system-file-cache
2018-05-20T07:50:13.923-0500 I CONTROL  [initandlisten]

Access control is not restricted because I want to experiment and do not wish to run into roadblocks. That would not be the case in a production environment. As mentioned, the shell connected to the MongoDB instance running on my local machine.

I am not going to attempt to connect to a remote instance running on a Linux machine.

I will now start the shell without connecting to a MongoDB instance:

C:\Temp\MongoDB>mongo --nodb
MongoDB shell version v3.6.4
>

We can now connect to our local MongoDB instance:

conn = new Mongo("127.0.0.1:27017")
connection to 127.0.0.1:27017

Note that JavaScript is case sensitive and you must use the configured port used by MongoDB to listen for connections. From a console with administrative rights:

C:\netstat -ab

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    0.0.0.0:80             Condor:0               LISTENING
 Can not obtain ownership information
  TCP    0.0.0.0:135            Condor:0               LISTENING
  RpcSs
 [svchost.exe]
  TCP    0.0.0.0:445            Condor:0               LISTENING
 Can not obtain ownership information
  TCP    0.0.0.0:1801           Condor:0               LISTENING
 [mqsvc.exe]
  TCP    0.0.0.0:1947           Condor:0               LISTENING
 [hasplms.exe]
  TCP    0.0.0.0:2103           Condor:0               LISTENING
 [mqsvc.exe]
  TCP    0.0.0.0:2105           Condor:0               LISTENING
 [mqsvc.exe]
  TCP    0.0.0.0:2107           Condor:0               LISTENING
 [mqsvc.exe]
  TCP    0.0.0.0:2179           Condor:0               LISTENING
 [vmms.exe]
  TCP    0.0.0.0:3306           Condor:0               LISTENING
 [mysqld.exe]
  TCP    0.0.0.0:5357           Condor:0               LISTENING
 Can not obtain ownership information
  TCP    0.0.0.0:7680           Condor:0               LISTENING
  DoSvc
 [svchost.exe]
  TCP    0.0.0.0:49664          Condor:0               LISTENING
 Can not obtain ownership information
  TCP    0.0.0.0:49665          Condor:0               LISTENING
  EventLog
 [svchost.exe]
  TCP    0.0.0.0:49666          Condor:0               LISTENING
  Schedule
 [svchost.exe]
  TCP    0.0.0.0:49672          Condor:0               LISTENING
 [lsass.exe]
  TCP    0.0.0.0:49717          Condor:0               LISTENING
 [spoolsv.exe]
  TCP    0.0.0.0:49732          Condor:0               LISTENING
 [mqsvc.exe]
  TCP    0.0.0.0:49739          Condor:0               LISTENING
 Can not obtain ownership information
  TCP    0.0.0.0:49838          Condor:0               LISTENING
  SessionEnv
 [svchost.exe]
  TCP    10.0.75.1:139          Condor:0               LISTENING
 Can not obtain ownership information
  TCP    10.0.75.1:5040         Condor:0               LISTENING
  CDPSvc
 [svchost.exe]
  TCP    127.0.0.1:1434         Condor:0               LISTENING
 [sqlservr.exe]
  TCP    127.0.0.1:5354         Condor:0               LISTENING
 [mDNSResponder.exe]
  TCP    127.0.0.1:27017        Condor:0               LISTENING
 [mongod.exe]
  TCP    127.0.0.1:27017        Condor:59161           ESTABLISHED
 [mongod.exe]
  TCP    127.0.0.1:59161        Condor:27017           ESTABLISHED
 [mongo.exe]
  TCP    169.254.80.80:139      Condor:0               LISTENING
 Can not obtain ownership information
  TCP    169.254.80.80:5040     Condor:0               LISTENING
  CDPSvc
 [svchost.exe]
  TCP    192.168.1.110:139      Condor:0               LISTENING
 Can not obtain ownership information
  TCP    192.168.1.110:54911    13.89.220.65:https     ESTABLISHED
  WpnService
 [svchost.exe]
^C
C:\

You can then look for the mongod.exe entry and find out the port number. By the way, the default MongoDB port number is:  27017. You could also find the listening port when you start MongoDB from a command prompt:

C:\mongod
2018-05-18T07:47:12.532-0700 I CONTROL  [initandlisten] MongoDB starting : pid=8028 port=27017 dbpath=C:\data\db\ 64-bit host=Condor
2018-05-18T07:47:12.533-0700 I CONTROL  [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2
2018-05-18T07:47:12.533-0700 I CONTROL  [initandlisten] db version v3.6.4
2018-05-18T07:47:12.533-0700 I CONTROL  [initandlisten] git version: d0181a711f7e7f39e60b5aeb1dc7097bf6ae5856
2018-05-18T07:47:12.533-0700 I CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.2o-fips  27 Mar 2018
2018-05-18T07:47:12.533-0700 I CONTROL  [initandlisten] allocator: tcmalloc
2018-05-18T07:47:12.534-0700 I CONTROL  [initandlisten] modules: none
2018-05-18T07:47:12.534-0700 I CONTROL  [initandlisten] build environment:
2018-05-18T07:47:12.534-0700 I CONTROL  [initandlisten]     distmod: 2008plus-ssl
2018-05-18T07:47:12.534-0700 I CONTROL  [initandlisten]     distarch: x86_64
2018-05-18T07:47:12.534-0700 I CONTROL  [initandlisten]     target_arch: x86_64
2018-05-18T07:47:12.534-0700 I CONTROL  [initandlisten] options: {}
2018-05-18T07:47:12.538-0700 I -        [initandlisten] Detected data files in C:\data\db\ created by the 'wiredTiger' storage engine, so setting the act
ive storage engine to 'wiredTiger'.
2018-05-18T07:47:12.538-0700 I STORAGE  [initandlisten] wiredtiger_open config: create,cache_size=11774M,session_max=20000,eviction=(threads_min=4,thread
s_max=4),config_base=false,statistics=(fast),cache_cursors=false,log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_
time=100000),statistics_log=(wait=0),verbose=(recovery_progress),
2018-05-18T07:47:13.138-0700 I STORAGE  [initandlisten] WiredTiger message [1526654833:137838][8028:140722514714960], txn-recover: Main recovery loop: st
arting at 9/4608
2018-05-18T07:47:13.439-0700 I STORAGE  [initandlisten] WiredTiger message [1526654833:438877][8028:140722514714960], txn-recover: Recovering log 9 throu
gh 10
2018-05-18T07:47:13.666-0700 I STORAGE  [initandlisten] WiredTiger message [1526654833:665878][8028:140722514714960], txn-recover: Recovering log 10 thro
ugh 10
2018-05-18T07:47:14.085-0700 I STORAGE  [initandlisten] WiredTiger message [1526654834:84907][8028:140722514714960], txn-recover: Set global recovery tim
estamp: 0
2018-05-18T07:47:14.450-0700 I CONTROL  [initandlisten]
2018-05-18T07:47:14.451-0700 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-05-18T07:47:14.451-0700 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2018-05-18T07:47:14.451-0700 I CONTROL  [initandlisten]
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten] ** WARNING: This server is bound to localhost.
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server.
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten] **          Start the server with --bind_ip 

&lt;address&gt; to specify which IP
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten] **          addresses it should serve responses from, or with --bind_ip_all to
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten] **          bind to all interfaces. If this behavior is desired, start the
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten] **          server with --bind_ip 127.0.0.1 to disable this warning.
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten]
2018-05-18T07:47:14.452-0700 I CONTROL  [initandlisten]
2018-05-18T07:47:14.453-0700 I CONTROL  [initandlisten] ** WARNING: The file system cache of this machine is configured to be greater than 40% of the tot
al memory. This can lead to increased memory pressure and poor performance.
2018-05-18T07:47:14.453-0700 I CONTROL  [initandlisten] See http://dochub.mongodb.org/core/wt-windows-system-file-cache
2018-05-18T07:47:14.453-0700 I CONTROL  [initandlisten]
2018-05-18T09:47:15.084-0500 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory 'C:/data/db/diagnostic.data'
2018-05-18T09:47:15.088-0500 I NETWORK  [initandlisten] waiting for connections on port 27017

Once connected to an instance, you can specify a database. The entire sequence is illustrated as follows:

C:\mongo --nodb
MongoDB shell version v3.6.4
conn = new Mongo("127.0.0.1:27017")
connection to 127.0.0.1:27017
db = conn.getDB("towns")
towns

To get help on commands one may issue the following:

>help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        sh.help()                    sharding helpers
        rs.help()                    replica set helpers
        help admin                   administrative help
        help connect                 connecting to a db help
        help keys                    key shortcuts
        help misc                    misc things to know
        help mr                      mapreduce

        show dbs                     show database names
        show collections             show collections in current database
        show users                   show users in current database
        show profile                 show most recent system.profile entries with time &gt;= 1ms
        show logs                    show the accessible logger names
        show log [name]              prints out the last segment of log in memory, 'global' is default
        use &lt;db_name&gt;                set current database
        db.foo.find()                list objects in collection foo
        db.foo.find( { a : 1 } )     list objects in foo where a == 1
        it                           result of the last line evaluated; use to further iterate
        DBQuery.shellBatchSize = x   set default number of items to display on shell
        exit                         quit the mongo shell

The most useful set of commands may be found in db.help() and db.mycoll.help(). This is illustrated by:

>db.help()
DB methods:
        db.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)]
        db.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor
        db.auth(username, password)
        db.cloneDatabase(fromhost)
        db.commandHelp(name) returns the help for the command
        db.copyDatabase(fromdb, todb, fromhost)
        db.createCollection(name, {size: ..., capped: ..., max: ...})
        db.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})
        db.createUser(userDocument)
        db.currentOp() displays currently executing operations in the db
        db.dropDatabase()
        db.eval() - deprecated
        db.fsyncLock() flush data to disk and lock server for backups
        db.fsyncUnlock() unlocks server following a db.fsyncLock()
        db.getCollection(cname) same as db['cname'] or db.cname
        db.getCollectionInfos([filter]) - returns a list that contains the names and options of the db's collections
        db.getCollectionNames()
        db.getLastError() - just returns the err msg string
        db.getLastErrorObj() - return full status object
        db.getLogComponents()
        db.getMongo() get the server connection object
        db.getMongo().setSlaveOk() allow queries on a replication slave server
        db.getName()
        db.getPrevError()
        db.getProfilingLevel() - deprecated
        db.getProfilingStatus() - returns if profiling is on and slow threshold
        db.getReplicationInfo()
        db.getSiblingDB(name) get the db at the same server as this one
        db.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set
        db.hostInfo() get details about the server's host
        db.isMaster() check replica primary status
        db.killOp(opid) kills the current operation in the db
        db.listCommands() lists all the db commands
        db.loadServerScripts() loads all the scripts in db.system.js
        db.logout()
        db.printCollectionStats()
        db.printReplicationInfo()
        db.printShardingStatus()
        db.printSlaveReplicationInfo()
        db.dropUser(username)
        db.repairDatabase()
        db.resetError()
        db.runCommand(cmdObj) run a database command.  if cmdObj is a string, turns it into {cmdObj: 1}
        db.serverStatus()
        db.setLogLevel(level,&lt;component&gt;)
        db.setProfilingLevel(level,slowms) 0=off 1=slow 2=all
        db.setWriteConcern(&lt;write concern doc&gt;) - sets the write concern for writes to the db
        db.unsetWriteConcern(&lt;write concern doc&gt;) - unsets the write concern for writes to the db
        db.setVerboseShell(flag) display extra information in shell output
        db.shutdownServer()
        db.stats()
        db.version() current version of the server
>

These commands are used on databases and the following are used for collections:

>db.mycoll.help()
DBCollection help
        db.mycoll.find().help() - show DBCursor help
        db.mycoll.bulkWrite( operations,&lt;optional params&gt; ) - bulk execute write operations, optional parameters are: w, wtimeout, j
        db.mycoll.count( query = {},&lt;optional params&gt; ) - count the number of documents that matches the query, optional parameters are: limit, skip, hint, maxTimeMS
        db.mycoll.copyTo(newColl) - duplicates collection by copying all documents to newColl; no indexes are copied.
        db.mycoll.convertToCapped(maxBytes) - calls {convertToCapped:'mycoll', size:maxBytes}} command
        db.mycoll.createIndex(keypattern[,options])
        db.mycoll.createIndexes([keypatterns],&lt;options&gt;)
        db.mycoll.dataSize()
        db.mycoll.deleteOne( filter,&lt;optional params&gt; ) - delete first matching document, optional parameters are: w, wtimeout, j
        db.mycoll.deleteMany( filter,&lt;optional params&gt; ) - delete all matching documents, optional parameters are: w, wtimeout, j
        db.mycoll.distinct( key, query,&lt;optional params&gt; ) - e.g. db.mycoll.distinct( 'x' ), optional parameters are: maxTimeMS
        db.mycoll.drop() drop the collection
        db.mycoll.dropIndex(index) - e.g. db.mycoll.dropIndex( "indexName" ) or db.mycoll.dropIndex( { "indexKey" : 1 } )
        db.mycoll.dropIndexes()
        db.mycoll.ensureIndex(keypattern[,options]) - DEPRECATED, use createIndex() instead
        db.mycoll.explain().help() - show explain help
        db.mycoll.reIndex()
        db.mycoll.find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return.
                                                      e.g. db.mycoll.find( {x:77} , {name:1, x:1} )
        db.mycoll.find(...).count()
        db.mycoll.find(...).limit(n)
        db.mycoll.find(...).skip(n)
        db.mycoll.find(...).sort(...)
        db.mycoll.findOne([query], [fields], [options], [readConcern])
        db.mycoll.findOneAndDelete( filter,&lt;optional params&gt; ) - delete first matching document, optional parameters are: projection, sort, maxTimeMS
        db.mycoll.findOneAndReplace( filter, replacement,&lt;optional params&gt; ) - replace first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument
        db.mycoll.findOneAndUpdate( filter, update,&lt;optional params&gt; ) - update first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument
        db.mycoll.getDB() get DB object associated with collection
        db.mycoll.getPlanCache() get query plan cache associated with collection
        db.mycoll.getIndexes()
        db.mycoll.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )
        db.mycoll.insert(obj)
        db.mycoll.insertOne( obj,&lt;optional params&gt; ) - insert a document, optional parameters are: w, wtimeout, j
        db.mycoll.insertMany( [objects],&lt;optional params&gt; ) - insert multiple documents, optional parameters are: w, wtimeout, j
        db.mycoll.mapReduce( mapFunction , reduceFunction ,&lt;optional params&gt; )
        db.mycoll.aggregate( [pipeline],&lt;optional params&gt; ) - performs an aggregation on a collection; returns a cursor
        db.mycoll.remove(query)
        db.mycoll.replaceOne( filter, replacement,&lt;optional params&gt; ) - replace the first matching document, optional parameters are: upsert, w, wtimeout, j
        db.mycoll.renameCollection( newName , &lt;dropTarget&gt; ) renames the collection.
        db.mycoll.runCommand( name ,&lt;options&gt; ) runs a db command with the given name where the first param is the collection name
        db.mycoll.save(obj)
        db.mycoll.stats({scale: N, indexDetails: true/false, indexDetailsKey: &lt;index key&gt;, indexDetailsName: &lt;index name&gt;})
        db.mycoll.storageSize() - includes free space allocated to this collection
        db.mycoll.totalIndexSize() - size in bytes of all the indexes
        db.mycoll.totalSize() - storage allocated for all data and indexes
        db.mycoll.update( query, object[, upsert_bool, multi_bool] ) - instead of two flags, you can pass an object with fields: upsert, multi
        db.mycoll.updateOne( filter, update,&lt;optional params&gt; ) - update the first matching document, optional parameters are: upsert, w, wtimeout, j
        db.mycoll.updateMany( filter, update,&lt;optional params&gt; ) - update all matching documents, optional parameters are: upsert, w, wtimeout, j
        db.mycoll.validate( &lt;full&gt; ) - SLOW
        db.mycoll.getShardVersion() - only for use with sharding
        db.mycoll.getShardDistribution() - prints statistics about data distribution in the cluster
        db.mycoll.getSplitKeysForChunks( &lt;maxChunkSize&gt; ) - calculates split points over all chunks and returns splitter function
        db.mycoll.getWriteConcern() - returns the write concern used for any operations on this collection, inherited from server/db if set
        db.mycoll.setWriteConcern( &lt;write concern doc&gt; ) - sets the write concern for writes to the collection
        db.mycoll.unsetWriteConcern( &lt;write concern doc&gt; ) - unsets the write concern for writes to the collection
        db.mycoll.latencyStats() - display operation latency histograms for this collection
>

Given that the shell implements JavaScript, if you wish to see what a function does, one can enter it into the shell omitting the parenthesis “()” as illustrated:

>db.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)");
        print("\tdb.commandHelp(name) returns the help for the command");
        print("\tdb.copyDatabase(fromdb, todb, fromhost)");
        print("\tdb.createCollection(name, {size: ..., capped: ..., max: ...})");
        print("\tdb.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions})");
        print("\tdb.createUser(userDocument)");
        print("\tdb.currentOp() displays currently executing operations in the db");
        print("\tdb.dropDatabase()");
        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.getPrevError()");
        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.dropUser(username)");
        print("\tdb.repairDatabase()");
        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,&lt;component&gt;)");
        print("\tdb.setProfilingLevel(level,slowms) 0=off 1=slow 2=all");
        print(
            "\tdb.setWriteConcern(&lt;write concern doc&gt;) - sets the write concern for writes to the db");
        print(
            "\tdb.unsetWriteConcern(&lt;write concern doc&gt;) - unsets the write concern for writes to the db");
        print("\tdb.setVerboseShell(flag) display extra information in shell output");
        print("\tdb.shutdownServer()");
        print("\tdb.stats()");
        print("\tdb.version() current version of the server");

        return __magicNoPrint;
    }
>

You can match the output of the call “> db.help()” to the output of what the unction does “> db.help”.

The book contains an example of finding out what the db.collection.update() function does.  The results illustrated in the book contain about half dozen lines of JavaScript.  The book that I am reading is part of the second edition released in June 2014 (about four years ago). Take a look at what the same example renders today:

>db.towns.update
function (query, obj, upsert, multi) {
    var parsed = this._parseUpdate(query, obj, upsert, multi);
    var query = parsed.query;
    var obj = parsed.obj;
    var upsert = parsed.upsert;
    var multi = parsed.multi;
    var wc = parsed.wc;
    var collation = parsed.collation;
    var arrayFilters = parsed.arrayFilters;

    var result = undefined;
    var startTime =
        (typeof(_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime();

    if (this.getMongo().writeMode() != "legacy") {
        var bulk = this.initializeOrderedBulkOp();
        var updateOp = bulk.find(query);

        if (upsert) {
            updateOp = updateOp.upsert();
        }

        if (collation) {
            updateOp.collation(collation);
        }

        if (arrayFilters) {
            updateOp.arrayFilters(arrayFilters);
        }

        if (multi) {
            updateOp.update(obj);
        } else {
            updateOp.updateOne(obj);
        }

        try {
            result = bulk.execute(wc).toSingleResult();
        } catch (ex) {
            if (ex instanceof BulkWriteError || ex instanceof WriteCommandError) {
                result = ex.toSingleResult();
            } else {
                // Other exceptions thrown
                throw Error(ex);
            }
        }
    } else {
        if (collation) {
            throw new Error("collation requires use of write commands");
        }

        if (arrayFilters) {
            throw new Error("arrayFilters requires use of write commands");
        }

        this.getMongo().update(this._fullName, query, obj, upsert, multi);

        // Enforce write concern, if required
        if (wc) {
            result = this.runCommand("getLastError", wc instanceof WriteConcern ? wc.toJSON() : wc);
        }
    }

    this._printExtraInfo("Updated", startTime);
    return result;
}
>

It is interesting to note that the implementation of the function now contains several dozen lines.  In the previous example I used the name of a test collection I am using. One can get the same results by using “db.mycoll.update” or “db.x.update” for short.

Now let’s explore running scripts with the shell.  For simplicity (will explain shortly) I exited the shell, moved to a different directory and restarted the MongoDB shell as follows:

C:\Temp\MongoDB&gt;
C:\Temp\MongoDB&gt;mongo
MongoDB shell version v3.6.4
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.4
Server has startup warnings:
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten]
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten]
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten] ** WARNING: This server is bound to localhost.
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server.
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten] **          Start the server with --bind_ip 

&lt;address&gt; to specify which IP
2018-05-18T09:48:04.808-0500 I CONTROL  [initandlisten] **          addresses it should serve responses from, or with --bind_ip_all to
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten] **          bind to all interfaces. If this behavior is desired, start the
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten] **          server with --bind_ip 127.0.0.1 to disable this warning.
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten]
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten]
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten] ** WARNING: The file system cache of this machine is configured to be greater than 40% of the
 total memory. This can lead to increased memory pressure and poor performance.
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten] See http://dochub.mongodb.org/core/wt-windows-system-file-cache
2018-05-18T09:48:04.809-0500 I CONTROL  [initandlisten]
>

The reason was to simplify access to the scripts based on the results of the following command:

>help admin
        ls([path])                      list files
        pwd()                           returns current directory
        listFiles([path])               returns file list
        hostname()                      returns name of this host
        cat(fname)                      returns contents of text file as a string
        removeFile(f)                   delete a file or directory
        load(jsfilename)                load and execute a .js file
        run(program[, args...])         spawn a program and wait for its completion
        runProgram(program[, args...])  same as run(), above
        sleep(m)                        sleep m milliseconds
        getMemInfo()                    diagnostic
>

One can see that among other things, we can get the path to the current folder e.g., pwd() and list its contents e.g., listFiles(); but there is no command that allows as to change the working directory i.e., cd().

You can call the mongo shell with one or more JavaScript scripts and they will be executed. Please note that when done, the mongo shell exits:

C:\Temp\MongoDB&gt;mongo script1.js script2.js script3.js
MongoDB shell version v3.6.4
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.4
loading file: script1.js
Hello John; this is script1.js !!!
loading file: script2.js
Hi John; this is script2.js !!!
loading file: script3.js
Hello; this is script3.js !!!

C:\Temp\MongoDB&gt;

This feature may be used to perform tasks on any MongoDB instance provided you have access to it. A script could write to a specific file, aggregate values from a desired collection. The possibilities are endless.

You may specify different options when invoking the shell. To get the list you may use the following:

C:\Temp\MongoDB&gt;mongo --help
MongoDB shell version v3.6.4
usage: mongo [options] [db address] [file names (ending in .js)]
db address can be:
  foo                   foo database on local machine
  192.168.0.5/foo       foo database on 192.168.0.5 machine
  192.168.0.5:9999/foo  foo database on 192.168.0.5 machine on port 9999
Options:
  --shell                             run the shell after executing files
  --nodb                              don't connect to mongod on startup - no
                                      'db address' arg expected
  --norc                              will not run the ".mongorc.js" file on
                                      start up
  --quiet                             be less chatty
  --port arg                          port to connect to
  --host arg                          server to connect to
  --eval arg                          evaluate javascript
  -h [ --help ]                       show this usage information
  --version                           show version information
  --verbose                           increase verbosity
  --ipv6                              enable IPv6 support (disabled by default)
  --disableJavaScriptJIT              disable the Javascript Just In Time
                                      compiler
  --disableJavaScriptProtection       allow automatic JavaScript function
                                      marshalling
  --ssl                               use SSL for all connections
  --sslCAFile arg                     Certificate Authority file for SSL
  --sslPEMKeyFile arg                 PEM certificate/key file for SSL
  --sslPEMKeyPassword arg             password for key in PEM file for SSL
  --sslCRLFile arg                    Certificate Revocation List file for SSL
  --sslAllowInvalidHostnames          allow connections to servers with
                                      non-matching hostnames
  --sslAllowInvalidCertificates       allow connections to servers with invalid
                                      certificates
  --sslFIPSMode                       activate FIPS 140-2 mode at startup
  --retryWrites                       automatically retry write operations upon
                                      transient network errors
  --jsHeapLimitMB arg                 set the js scope's heap size limit

Authentication Options:
  -u [ --username ] arg               username for authentication
  -p [ --password ] arg               password for authentication
  --authenticationDatabase arg        user source (defaults to dbname)
  --authenticationMechanism arg       authentication mechanism
  --gssapiServiceName arg (=mongodb)  Service name to use when authenticating
                                      using GSSAPI/Kerberos
  --gssapiHostName arg                Remote host name to use for purpose of
                                      GSSAPI/Kerberos authentication

file names: a list of files to run. files have to end in .js and will exit after unless --shell is specified

C:\Temp\MongoDB;

When we invoked the scripts we could eliminate some verbose by using the following option:

C:\Temp\MongoDB&gt;mongo --quiet script1.js script2.js script3.js
loading file: script1.js
Hello John; this is script1.js !!!
loading file: script2.js
Hi John; this is script2.js !!!
loading file: script3.js
Hello; this is script3.js !!!

C:\Temp\MongoDB&gt;

Any script may be executed from inside the shell. To avoid adding the path to the scripts I decided to start the mongo shell in the folder holding the scripts. The following commands may be used to determine if we are in the proper place:

>pwd()
C:\Temp\MongoDB
>listFiles(pwd())
[
        {
                "name" : "C:/Temp/MongoDB/script1.js",
                "baseName" : "script1.js",
                "isDirectory" : false,
                "size" : 44
        },
        {
                "name" : "C:/Temp/MongoDB/script2.js",
                "baseName" : "script2.js",
                "isDirectory" : false,
                "size" : 41
        },
        {
                "name" : "C:/Temp/MongoDB/script3.js",
                "baseName" : "script3.js",
                "isDirectory" : false,
                "size" : 39
        }
]
>

Now let’s run them:

>load("script1.js")
Hello John; this is script1.js !!!
true
>load("script2.js")
Hi John; this is script2.js !!!
true
>load("script3.js")
Hello; this is script3.js !!!
true
>

The idea is that you can write scripts that include db variables but not shell helpers. For example:

>load("script4.js")
2018-05-20T08:10:50.297-0500 E QUERY    [thread1] [script4.js:2:21] SyntaxError: missing ) after argument list
Stack trace:
@(shell):1:1
----------
2018-05-20T08:10:50.298-0500 E QUERY    [thread1] Error: error loading js file: script4.js @(shell):1:1
>

The previous script did not work. The modified script works:

>load("script4.js")
{
        "databases" : [
                {
                        "name" : "admin",
                        "sizeOnDisk" : 32768,
                        "empty" : false
                },
                {
                        "name" : "config",
                        "sizeOnDisk" : 12288,
                        "empty" : false
                },
                {
                        "name" : "local",
                        "sizeOnDisk" : 73728,
                        "empty" : false
                },
                {
                        "name" : "towns",
                        "sizeOnDisk" : 32768,
                        "empty" : false
                }
        ],
        "totalSize" : 151552,
        "ok" : 1
}
true
>

The contents of the script4.js follows:

// **** does NOT work ****
//print(show dbs);

// **** does work ****
var dbs = db.getMongo().getDBs();
printjson(dbs);

There is good documentation and tutorials at the MongoDB (https://docs.mongodb.com/manual) web site.  For example, the book just mentions a few of the equivalents for the helpers. The MongoDB web site shows:

Shell Helpers JavaScript Equivalents
show dbs, show databases db.adminCommand(‘listDatabases’)
use <db> db = db.getSiblingDB(‘<db>’)
show collections db.getCollectionNames()
show users db.getUsers()
show roles db.getRoles({showBuiltinRoles: true})
show log <logname> db.adminCommand({ ‘getLog’ : ‘<logname>’ })
show logs db.adminCommand({ ‘getLog’ : ‘*’ })
it cursor = db.collection.find()

if ( cursor.hasNext() ){

cursor.next();

}

You can use scripts to define variables and methods. Let’s load a script that helps us connect to a specified database:

>typeof connectTo
undefined
>load("connect_to.js")
true
>typeof connectTo
function
>connectTo()
<<< entering ...
<<< about to exit !!!

I always develop software no matter how simple it may be, using a Test Driven Development (TTD) approach. The contents of the initial script follow:

/**
 * 
 */
 var connectTo = function() {
     print("&lt;&lt;&lt; entering ...");
     
     
     print("&lt;&lt;&lt; about to exit !!!");
 }

# **** final connect_to.js script ****
/**
 * Simple function to connect to our test database
 */
 var connectTo = function(url, port, dbName) {
     
     // **** assign default values; if needed ****
     if (url === undefined) {
         url = "127.0.0.1";
     }
     if (port === undefined) {
         port = 27017;
     }
     if (dbName === undefined) {
         dbName = "towns";
     }
     
     // **** display arguments ****
     print("&lt;&lt;&lt;    url: " + url);
     print("&lt;&lt;&lt;   port: " + port);
     print("&lt;&lt;&lt; dbName: " + dbName);
     
     // **** build the connection string ****
     var connStr = url+":"+port+"/"+dbName;
     print("&lt;&lt;&lt; conStr: " + connStr);
     
     // **** connect to the database ****
     db = connect(connStr);
     printjson(db);
     
     // **** return the DB object ****
     return db;
 }

Do not forget to load and execute the script as you edit and test it:

>load("connect_to.js")
true
>connectTo()
<<< url: 127.0.0.1
<<< port: 27017
<<< dbName: towns
<<< conStr: 127.0.0.1:27017/towns connecting to: mongodb://127.0.0.1:27017/towns MongoDB server version: 3.6.4 towns towns;

If you fail to load it then the output will remain constant not reflecting your changes.

Will now run the ping.exe command from the shell:

>run("c:/windows/system32/ping.exe", "-n", "7", "192.168.1.110")
2018-05-20T15:56:30.705-0500 I -        [thread1] shell: started program (sh8676):  c:/windows/system32/ping.exe -n 7 192.168.1.110
sh8676|
sh8676| Pinging 192.168.1.110 with 32 bytes of data:
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh8676| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128 sh8676| sh8676| Ping statistics for 192.168.1.110: sh8676| Packets: Sent = 7, Received = 7, Lost = 0 (0% loss), sh8676| Approximate round trip times in milli-seconds: sh8676| Minimum = 0ms, Maximum = 0ms, Average = 0ms 0 &gt;

The ping program executes sending 7 packets to the target machine.

In this example a script is invoked to use run() with the ping command:

>ls()
[
        "./connect_to.js",
        "./run_cmds.js",
        "./script1.js",
        "./script2.js",
        "./script3.js",
        "./script4.js"
]
>cat("run_cmds.js")
// **** works ****
run("c:/Windows/system32/ping.exe", "-n", "7", "192.168.1.110");

>load("run_cmds.js")
2018-05-20T16:02:13.996-0500 I -        [thread1] shell: started program (sh10840):  c:/Windows/system32/ping.exe -n 7 192.168.1.110
sh10840|
sh10840| Pinging 192.168.1.110 with 32 bytes of data:
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128
sh10840| Reply from 192.168.1.110: bytes=32 time&lt;1ms TTL=128 sh10840| sh10840| Ping statistics for 192.168.1.110: sh10840| Packets: Sent = 7, Received = 7, Lost = 0 (0% loss), sh10840| Approximate round trip times in milli-seconds: sh10840| Minimum = 0ms, Maximum = 0ms, Average = 0ms true &gt;

I could continue for days or weeks experimenting with different commands. If interested in learning MongoDB I definitely recommend the “MongoDB – The definitive guide”. In addition I would also suggest the different online courses offered by the MongoDB University. At this time I have registered for: M101J: MongoDB for Java Developers Class starts May 29, 2018.

If you have comments or questions regarding this or any other post in this blog please leave me a message at the end of this post.Enjoy;

John

john.canessa@gmail.com

@john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.