Learn MongoDB With Me

Introduction

Here, we are going to do some exercises with MongoDB. We will be talking about Mongo Shell, how we can configure MongoDB, and what Indexes are in MongoDB, and more. We all know what Indexing is. You might have already done that with relational databases like SQL and MySQL. Have you every done indexing for your MongoDB? If your answer is "no," no worries! Here, we are going to see indexes in MongoDB. If it is a "yes," please read this post and correct me if I am wrong anywhere. Let's begin now.

Prerequisites

I hope you  have a basic idea about MongoDB. If not, I strongly recommend you read these posts. Now that you have a basic idea, I am assuming that you have already set up the environment for MongoDB development. Let's recall what you might have done so far.

  1. Install MongoDB
  2. Set the environment variable for MongoDB
  3. Start the MongoDB services

To set the environment variable for MongoDB, you may have to add a new path to the system variable path with the value as "C:\Program Files\MongoDB\Server\3.4\bin", please note that the version number will be varied according to your MongoDB version. Once you are done with the above steps, you should be able to start both Mongo server and Mongo shell from the command line interface.

Setting up MongoDB using CLI

Now, let's just open our command line interface, and create the data directory for Mongo. We will have to create a directory for the same. Please go along with the below commands.

  1. md \data md \data\db mongod  

Now, let's open a new CLI and run the command "mongo". Please do not worry about the warnings you are getting. We are not working in production data, we may not need to secure and optimize it.



Exploring MongoDB

Once you are connected to MongoDB, by default, you are connected to test DB. You can check that by running the command.

  1. MongoDB Enterprise > db  
Playing with Mongo Shell

Let's just use a new database now.

  1. MongoDB Enterprise > use MongoIndex switched to db MongoIndex MongoDB Enterprise >  

Please note that the database MongoIndex doesn't exist as of now, as we haven't created it. Still, Mongo just switched our context to the new database. You can see this if you run the command

show dbs

The database will be created once we insert any document associated with it. Now we are going to create a new collection called "User", so once we made the entry to this collection, the database will also be created automatically. Let's do that.

  1. MongoDB Enterprise > db.users.insert({"name":"Sibees Venu"}) WriteResult({ "nInserted" : 1 }) MongoDB Enterprise >  

Now, if you run the "show dbs" command again, the database MongoIndex will show up. If you ever need to see the collections you have in the DB, you just need to run the command "show collections".

  1. MongoDB Enterprise > show collections users MongoDB Enterprise >  

The MongoDB is very friendly when it comes to data, it doesn't require any schema to get it started. The learning is so easy, am I right?

The other benefit of MongoDB is its JavaScript interpreted shell, where we can actually type JavaScript code and run. To test it out, let's create a variable and use it.

  1. MongoDB Enterprise > var name = "Sibeesh Venu" MongoDB Enterprise > name Sibeesh Venu MongoDB Enterprise >  

This way, we can interact with the database with a JavaScript program. Now let's go ahead and create a collection called "Numbers" and insert 26,000 rows in it. So how are we going to do that? Yes, you are right, we are going to write a for loop, the mongo shell gives that kind of flexibility. Let's see that in action.

  1. MongoDB Enterprise > for(i=0;i<=26000;i++){  
  2. ... db.Numbers.insert({  
  3. ... "number":i  
  4. ... })  
  5. ... }  
  6. WriteResult({ "nInserted" : 1 })  
  7. MongoDB Enterprise >  

So we have done that. Note that, we are able to break the commands into multiple lines, this allows us to break the complex codes to much readable format in the shell itself. Sounds good?

Even though we have inserted 26,000 rows, it always shows,"nInserted" : 1 this is because it is counting a number of operations, not the individual documents. Let's see this by checking the count now.

  1. MongoDB Enterprise > db.numbers.count()  
  2. 0  
  3. MongoDB Enterprise > db.Numbers.count()  
  4. 26001  
  5. MongoDB Enterprise >  

Please note that it is case sensitive.

Indexes in MongoDB

Now if you need to see any particular record, you can always write the query in the shell as follows.

  1. MongoDB Enterprise > db.Numbers.find(  
  2. ... {"number":24000}  
  3. ... )  
  4. "_id" : ObjectId("5a8d3be2020a0071d115cf62"), "number" : 24000 }  
  5. MongoDB Enterprise >  

So in the query, we are using the function "find" with the filter "number: 24000", so that the Mongo can return the record which has the number value as 24000. Now that we have got the output we needed, would you like to see what just happened in the background? To do so, we can use the function "explain()".

  1. MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain()  
  2. {  
  3.         "queryPlanner" : {  
  4.                 "plannerVersion" : 1,  
  5.                 "namespace" : "MongoIndex.Numbers",  
  6.                 "indexFilterSet" : false,  
  7.                 "parsedQuery" : {  
  8.                         "number" : {  
  9.                                 "$eq" : 24000  
  10.                         }  
  11.                 },  
  12.                 "winningPlan" : {  
  13.                         "stage" : "COLLSCAN",  
  14.                         "filter" : {  
  15.                                 "number" : {  
  16.                                         "$eq" : 24000  
  17.                                 }  
  18.                         },  
  19.                         "direction" : "forward"  
  20.                 },  
  21.                 "rejectedPlans" : [ ]  
  22.         },  
  23.         "serverInfo" : {  
  24.                 "host" : "PC292716",  
  25.                 "port" : 27017,  
  26.                 "version" : "3.4.9",  
  27.                 "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"  
  28.         },  
  29.         "ok" : 1  
  30. }  
  31. MongoDB Enterprise >  

And, if you need to get more information about the execution, you can pass the parameter "executionStats" to the "explain" function.

The parameter is always case sensitive, you will get an errors as below, if you give it wrong. So please make sure you are passing executionStats not executionstats.

"MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain("executionstats") 2018-02-21T15:12:34.197+0530 E QUERY [thread1] Error: explain verbosity must be one of {'queryPlanner','executionStats','allPlansExecution'} :
parseVerbosity@src/mongo/shell/explainable.js:22:1 constructor@src/mongo/shell/explain_query.js:83:27 DBQuery.prototype.explain@src/mongo/shell/query.js:520:24 @(shell):1:1"

  1. MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain("executionStats")  
  2. {  
  3.         "queryPlanner" : {  
  4.                 "plannerVersion" : 1,  
  5.                 "namespace" : "MongoIndex.Numbers",  
  6.                 "indexFilterSet" : false,  
  7.                 "parsedQuery" : {  
  8.                         "number" : {  
  9.                                 "$eq" : 24000  
  10.                         }  
  11.                 },  
  12.                 "winningPlan" : {  
  13.                         "stage" : "COLLSCAN",  
  14.                         "filter" : {  
  15.                                 "number" : {  
  16.                                         "$eq" : 24000  
  17.                                 }  
  18.                         },  
  19.                         "direction" : "forward"  
  20.                 },  
  21.                 "rejectedPlans" : [ ]  
  22.         },  
  23.         "executionStats" : {  
  24.                 "executionSuccess" : true,  
  25.                 "nReturned" : 1,  
  26.                 "executionTimeMillis" : 13,  
  27.                 "totalKeysExamined" : 0,  
  28.                 "totalDocsExamined" : 26001,  
  29.                 "executionStages" : {  
  30.                         "stage" : "COLLSCAN",  
  31.                         "filter" : {  
  32.                                 "number" : {  
  33.                                         "$eq" : 24000  
  34.                                 }  
  35.                         },  
  36.                         "nReturned" : 1,  
  37.                         "executionTimeMillisEstimate" : 11,  
  38.                         "works" : 26003,  
  39.                         "advanced" : 1,  
  40.                         "needTime" : 26001,  
  41.                         "needYield" : 0,  
  42.                         "saveState" : 203,  
  43.                         "restoreState" : 203,  
  44.                         "isEOF" : 1,  
  45.                         "invalidates" : 0,  
  46.                         "direction" : "forward",  
  47.                         "docsExamined" : 26001  
  48.                 }  
  49.         },  
  50.         "serverInfo" : {  
  51.                 "host" : "PC292716",  
  52.                 "port" : 27017,  
  53.                 "version" : "3.4.9",  
  54.                 "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"  
  55.         },  
  56.         "ok" : 1  
  57. }  
  58. MongoDB Enterprise >  

Now you can see more information on the execution of how much time it took for the execution and how many docs it is examined etc. If you have noticed, it has examined all the 26001 records and took 13 milliseconds. That's just a case where we had a small number of records in the table, what if, we have millions of records in it? And examining all the records would be a bad idea, am I right? So what do we do at that time? What would be a permanent solution for this? This is where the importance of Indexes comes into action.

Let's create an Index for the number that we are going to search.

  1. MongoDB Enterprise > db.Numbers.createIndex({number:1})  
  2. {  
  3.         "createdCollectionAutomatically" : false,  
  4.         "numIndexesBefore" : 1,  
  5.         "numIndexesAfter" : 2,  
  6.         "ok" : 1  
  7. }  
  8. MongoDB Enterprise >  

Here the number is a special variable, not a string. As you can see, we had created the index. You can see that the property value of createdCollectionAutomatically is false, as the collection had already created and it didn't have to create it again.

Let's run our find query again.

  1. MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain("executionStats")  
  2. {  
  3.         "queryPlanner" : {  
  4.                 "plannerVersion" : 1,  
  5.                 "namespace" : "MongoIndex.Numbers",  
  6.                 "indexFilterSet" : false,  
  7.                 "parsedQuery" : {  
  8.                         "number" : {  
  9.                                 "$eq" : 24000  
  10.                         }  
  11.                 },  
  12.                 "winningPlan" : {  
  13.                         "stage" : "FETCH",  
  14.                         "inputStage" : {  
  15.                                 "stage" : "IXSCAN",  
  16.                                 "keyPattern" : {  
  17.                                         "number" : 1  
  18.                                 },  
  19.                                 "indexName" : "number_1",  
  20.                                 "isMultiKey" : false,  
  21.                                 "multiKeyPaths" : {  
  22.                                         "number" : [ ]  
  23.                                 },  
  24.                                 "isUnique" : false,  
  25.                                 "isSparse" : false,  
  26.                                 "isPartial" : false,  
  27.                                 "indexVersion" : 2,  
  28.                                 "direction" : "forward",  
  29.                                 "indexBounds" : {  
  30.                                         "number" : [  
  31.                                                 "[24000.0, 24000.0]"  
  32.                                         ]  
  33.                                 }  
  34.                         }  
  35.                 },  
  36.                 "rejectedPlans" : [  
  37.                         {  
  38.                                 "stage" : "FETCH",  
  39.                                 "inputStage" : {  
  40.                                         "stage" : "IXSCAN",  
  41.                                         "keyPattern" : {  
  42.                                                 "number" : 24000  
  43.                                         },  
  44.                                         "indexName" : "number_24000",  
  45.                                         "isMultiKey" : false,  
  46.                                         "multiKeyPaths" : {  
  47.                                                 "number" : [ ]  
  48.                                         },  
  49.                                         "isUnique" : false,  
  50.                                         "isSparse" : false,  
  51.                                         "isPartial" : false,  
  52.                                         "indexVersion" : 2,  
  53.                                         "direction" : "forward",  
  54.                                         "indexBounds" : {  
  55.                                                 "number" : [  
  56.                                                         "[24000.0, 24000.0]"  
  57.                                                 ]  
  58.                                         }  
  59.                                 }  
  60.                         }  
  61.                 ]  
  62.         },  
  63.         "executionStats" : {  
  64.                 "executionSuccess" : true,  
  65.                 "nReturned" : 1,  
  66.                 "executionTimeMillis" : 36,  
  67.                 "totalKeysExamined" : 1,  
  68.                 "totalDocsExamined" : 1,  
  69.                 "executionStages" : {  
  70.                         "stage" : "FETCH",  
  71.                         "nReturned" : 1,  
  72.                         "executionTimeMillisEstimate" : 0,  
  73.                         "works" : 3,  
  74.                         "advanced" : 1,  
  75.                         "needTime" : 0,  
  76.                         "needYield" : 0,  
  77.                         "saveState" : 1,  
  78.                         "restoreState" : 1,  
  79.                         "isEOF" : 1,  
  80.                         "invalidates" : 0,  
  81.                         "docsExamined" : 1,  
  82.                         "alreadyHasObj" : 0,  
  83.                         "inputStage" : {  
  84.                                 "stage" : "IXSCAN",  
  85.                                 "nReturned" : 1,  
  86.                                 "executionTimeMillisEstimate" : 0,  
  87.                                 "works" : 2,  
  88.                                 "advanced" : 1,  
  89.                                 "needTime" : 0,  
  90.                                 "needYield" : 0,  
  91.                                 "saveState" : 1,  
  92.                                 "restoreState" : 1,  
  93.                                 "isEOF" : 1,  
  94.                                 "invalidates" : 0,  
  95.                                 "keyPattern" : {  
  96.                                         "number" : 1  
  97.                                 },  
  98.                                 "indexName" : "number_1",  
  99.                                 "isMultiKey" : false,  
  100.                                 "multiKeyPaths" : {  
  101.                                         "number" : [ ]  
  102.                                 },  
  103.                                 "isUnique" : false,  
  104.                                 "isSparse" : false,  
  105.                                 "isPartial" : false,  
  106.                                 "indexVersion" : 2,  
  107.                                 "direction" : "forward",  
  108.                                 "indexBounds" : {  
  109.                                         "number" : [  
  110.                                                 "[24000.0, 24000.0]"  
  111.                                         ]  
  112.                                 },  
  113.                                 "keysExamined" : 1,  
  114.                                 "seeks" : 1,  
  115.                                 "dupsTested" : 0,  
  116.                                 "dupsDropped" : 0,  
  117.                                 "seenInvalidated" : 0  
  118.                         }  
  119.                 }  
  120.         },  
  121.         "serverInfo" : {  
  122.                 "host" : "PC292716",  
  123.                 "port" : 27017,  
  124.                 "version" : "3.4.9",  
  125.                 "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"  
  126.         },  
  127.         "ok" : 1  
  128. }  
  129. MongoDB Enterprise >  

As we have given the index on what exactly we are going to search, it just examined only that document when we run the query. That's why the value of the property totalDocsExamined is 1. Indexing will not have many impacts on the database which has few records in it, but it has a massive effect on very large data sets which has millions of records in it. Using this simple Indexe can reduce the execution time to almost nothing.

And, we are done with this post. I will be posting the continuation part of this series very soon.

Conclusion

Thanks a lot for reading. Did I miss anything that you may think is needed? Did you find this post useful? I hope you liked this article. Please share your valuable suggestions and feedback.

Your turn. What do you think?

A blog isn’t a blog without comments, but do try to stay on topic. If you have a question unrelated to this post, you’re better off posting it on C# Corner, Code Project, Stack Overflow, Asp.Net Forum instead of commenting here. Tweet or email me a link to your question there and I’ll definitely try to help if I can.

Please see this article on my blog here.