Learn MongoDB With Me

[toc]

Introduction

This is going to be a series of article on MongoDB. Here we are going to do some exercises with MongoDB, we will be talking about Mongo Shell, how can we configure MongoDB?, What are Indexes in MongoDB etc. We all know what an Indexes is, you might have already done that with any 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 might have got a basic information about MongoDB, if not, I strongly recommend you to 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 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.

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, as 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 MongoDB Enterprise > db

Playing with Mongo Shell

Let’s just use a new database now.

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

Please be noted 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.

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”.

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.

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 creating 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.

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

So we have done that. Note that, we are able to break the commands into multiple lines, this allows 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.

MongoDB Enterprise > db.numbers.count()
0
MongoDB Enterprise > db.Numbers.count()
26001
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.

MongoDB Enterprise > db.Numbers.find(
... {"number":24000}
... )
{ "_id" : ObjectId("5a8d3be2020a0071d115cf62"), "number" : 24000 }
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()”.

MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "MongoIndex.Numbers",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "number" : {
                                "$eq" : 24000
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "number" : {
                                        "$eq" : 24000
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "PC292716",
                "port" : 27017,
                "version" : "3.4.9",
                "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
        },
        "ok" : 1
}
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″

MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "MongoIndex.Numbers",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "number" : {
                                "$eq" : 24000
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "number" : {
                                        "$eq" : 24000
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 13,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 26001,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "number" : {
                                        "$eq" : 24000
                                }
                        },
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 11,
                        "works" : 26003,
                        "advanced" : 1,
                        "needTime" : 26001,
                        "needYield" : 0,
                        "saveState" : 203,
                        "restoreState" : 203,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "direction" : "forward",
                        "docsExamined" : 26001
                }
        },
        "serverInfo" : {
                "host" : "PC292716",
                "port" : 27017,
                "version" : "3.4.9",
                "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
        },
        "ok" : 1
}
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, that we had only less 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.

MongoDB Enterprise > db.Numbers.createIndex({number:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
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.

MongoDB Enterprise > db.Numbers.find( {"number":24000} ).explain("executionStats")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "MongoIndex.Numbers",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "number" : {
                                "$eq" : 24000
                        }
                },
                "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                        "number" : 1
                                },
                                "indexName" : "number_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "number" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "number" : [
                                                "[24000.0, 24000.0]"
                                        ]
                                }
                        }
                },
                "rejectedPlans" : [
                        {
                                "stage" : "FETCH",
                                "inputStage" : {
                                        "stage" : "IXSCAN",
                                        "keyPattern" : {
                                                "number" : 24000
                                        },
                                        "indexName" : "number_24000",
                                        "isMultiKey" : false,
                                        "multiKeyPaths" : {
                                                "number" : [ ]
                                        },
                                        "isUnique" : false,
                                        "isSparse" : false,
                                        "isPartial" : false,
                                        "indexVersion" : 2,
                                        "direction" : "forward",
                                        "indexBounds" : {
                                                "number" : [
                                                        "[24000.0, 24000.0]"
                                                ]
                                        }
                                }
                        }
                ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 1,
                "executionTimeMillis" : 36,
                "totalKeysExamined" : 1,
                "totalDocsExamined" : 1,
                "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 1,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 3,
                        "advanced" : 1,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 1,
                        "restoreState" : 1,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "docsExamined" : 1,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 1,
                                "executionTimeMillisEstimate" : 0,
                                "works" : 2,
                                "advanced" : 1,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 1,
                                "restoreState" : 1,
                                "isEOF" : 1,
                                "invalidates" : 0,
                                "keyPattern" : {
                                        "number" : 1
                                },
                                "indexName" : "number_1",
                                "isMultiKey" : false,
                                "multiKeyPaths" : {
                                        "number" : [ ]
                                },
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 2,
                                "direction" : "forward",
                                "indexBounds" : {
                                        "number" : [
                                                "[24000.0, 24000.0]"
                                        ]
                                },
                                "keysExamined" : 1,
                                "seeks" : 1,
                                "dupsTested" : 0,
                                "dupsDropped" : 0,
                                "seenInvalidated" : 0
                        }
                }
        },
        "serverInfo" : {
                "host" : "PC292716",
                "port" : 27017,
                "version" : "3.4.9",
                "gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
        },
        "ok" : 1
}
MongoDB Enterprise >

As we had 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 Indexes can reduce the execution time to almost nothing.

With that, we are done with this post. I will be posting the continuation part of this series very soon. Till then, bye.

Conclusion

Thanks a lot for reading. Did I miss anything that you may think which is needed? Could you find this post as useful? I hope you liked this article. Please share me 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.

Kindest Regards
Sibeesh Venu

 

 

Leave a Reply

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

Serverless 360