Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Learn MongoDB With Me

DZone's Guide to

Learn MongoDB With Me

In this introductory post of a series on MongoDB, learn how using Indexes can reduce your execution time to almost nothing.

· Database Zone ·
Free Resource

Download the Altoros NoSQL Performance Benchmark 2018. Compare top NoSQL solutions – Couchbase Server v5.5, MongoDB v3.6, and DataStax Enterprise v6 (Cassandra).

This is going to be a series of article on MongoDB. We are going to do some exercises with MongoDB, talk about Mongo Shell, learn how to configure MongoDB, learn what Indexes are in MongoDB, etc. We all know what an Index is; you might have already done that with any relational databases like SQL and MySQL. Have you ever done indexing for 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 now know some basic information about MongoDB. If not, I strongly recommend that you read these posts. 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 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 vary 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.

md \data
md \data\db
mongod

Now let's open a new CLI and run the command mongo. Don't worry about the warnings get, as we are not working in production data and we may not need to secure and optimize it.

Exploring MongoDB

Once you are connected to MongoDB, by default, you are connected to a 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 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 make 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 >

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 it. 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 create a collection called Numbers and insert 26,000 rows in it. We going to do that with a for loop. The Mongo Shell gives that kind of flexibility. Let's see it 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 us to break the complex codes to a more readable format in the Shell itself. Sound good?

Even though we have inserted 26,000 rows, it always shows "nInserted" : 1 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 Mongo can return the record with a number value of 24,000. Now that we have the output we needed, would you like to see what just happened in the background? Uuse 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 error as shown below if you write 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 such as how much time it took for the execution and how many docs it examined. As you can see, it has examined all 26,001 records and took 13 milliseconds. That's just one case, where we had only a fewer number of records in the table. What if we have millions of records in it? Examining all the records would be a bad idea. What should we do? 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 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 information on what exactly we are going to search, it examines only that document when we run the query. That's why the value of the property totalDocsExamined is 1. Indexing will not have much impact on a database that has few records in it, but it has a massive effect on very large datasets that have millions of records. Using 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. 

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

Download the whitepaper, Moving From Relational to NoSQL: How to Get Started. We’ll take you step by step through your first NoSQL project.

Topics:
database ,tutorial ,mongodb ,execution ,cli ,mongo shell

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}