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 <address> 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 >= 1ms show logs show the accessible logger names show log [name] prints out the last segment of log in memory, 'global' is default use <db_name> 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,<component>) db.setProfilingLevel(level,slowms) 0=off 1=slow 2=all db.setWriteConcern(<write concern doc>) - sets the write concern for writes to the db db.unsetWriteConcern(<write concern doc>) - 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,<optional params> ) - bulk execute write operations, optional parameters are: w, wtimeout, j db.mycoll.count( query = {},<optional params> ) - 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],<options>) db.mycoll.dataSize() db.mycoll.deleteOne( filter,<optional params> ) - delete first matching document, optional parameters are: w, wtimeout, j db.mycoll.deleteMany( filter,<optional params> ) - delete all matching documents, optional parameters are: w, wtimeout, j db.mycoll.distinct( key, query,<optional params> ) - 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,<optional params> ) - delete first matching document, optional parameters are: projection, sort, maxTimeMS db.mycoll.findOneAndReplace( filter, replacement,<optional params> ) - replace first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument db.mycoll.findOneAndUpdate( filter, update,<optional params> ) - 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,<optional params> ) - insert a document, optional parameters are: w, wtimeout, j db.mycoll.insertMany( [objects],<optional params> ) - insert multiple documents, optional parameters are: w, wtimeout, j db.mycoll.mapReduce( mapFunction , reduceFunction ,<optional params> ) db.mycoll.aggregate( [pipeline],<optional params> ) - performs an aggregation on a collection; returns a cursor db.mycoll.remove(query) db.mycoll.replaceOne( filter, replacement,<optional params> ) - replace the first matching document, optional parameters are: upsert, w, wtimeout, j db.mycoll.renameCollection( newName , <dropTarget> ) renames the collection. db.mycoll.runCommand( name ,<options> ) 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: <index key>, indexDetailsName: <index name>}) 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,<optional params> ) - update the first matching document, optional parameters are: upsert, w, wtimeout, j db.mycoll.updateMany( filter, update,<optional params> ) - update all matching documents, optional parameters are: upsert, w, wtimeout, j db.mycoll.validate( <full> ) - SLOW db.mycoll.getShardVersion() - only for use with sharding db.mycoll.getShardDistribution() - prints statistics about data distribution in the cluster db.mycoll.getSplitKeysForChunks( <maxChunkSize> ) - 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( <write concern doc> ) - sets the write concern for writes to the collection db.mycoll.unsetWriteConcern( <write concern doc> ) - 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,<component>)"); print("\tdb.setProfilingLevel(level,slowms) 0=off 1=slow 2=all"); print( "\tdb.setWriteConcern(<write concern doc>) - sets the write concern for writes to the db"); print( "\tdb.unsetWriteConcern(<write concern doc>) - 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> 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-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 <address> 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>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>
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>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>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>
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("<<< entering ..."); print("<<< 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("<<< url: " + url); print("<<< port: " + port); print("<<< dbName: " + dbName); // **** build the connection string **** var connStr = url+":"+port+"/"+dbName; print("<<< 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<1ms TTL=128 sh8676| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh8676| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh8676| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh8676| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh8676| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh8676| Reply from 192.168.1.110: bytes=32 time<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 >
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<1ms TTL=128 sh10840| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh10840| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh10840| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh10840| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh10840| Reply from 192.168.1.110: bytes=32 time<1ms TTL=128 sh10840| Reply from 192.168.1.110: bytes=32 time<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 >
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