MongoDB

MongoDB

Hi Coders! In this article, we will be talking about basic commands in MongoDB.

INTRODUCTION

First, let me tell you some basic things about MongoDB.

MongoDB is a type of NoSQL database. NoSQL(Not Only SQL). Just like we have tables in MySQL, we have collections in MongoDB. Inside tables we have rows, here inside collections, we have documents. MongoDB stores data in a JSON-like format.

Hence, just like we have attributes for tables, in MySQL, here we have keys inside documents. But there is a slight difference. In Mysql, we had to predefine the structure of the tables. In MongoDB, each document can have a different set of [key: value] pairs. You will understand this in a while.

I think this introduction is enough. Now we should start.

COMMANDS

I hope you have installed MongoDB on your Devices. While running the commands, you should keep in mind that, unlike MySQL, MongoDB is case-sensitive. I will be soon uploading an article, on how to install MongoDB.

OPENING MongoDB

To open the MongoDB in the terminal, you have to run the command:

mongosh

mongosh

LISTING DATABASES

The command for listing all the databases:

In MongoDB, it is not necessary to end a statement with a semicolon.

1.show databases.

2.show dbs. // This command is a shortcut.

show databases;
show dbs;

Both of them will list the databases.

CREATING A DATABASE

In MongoDB, if we want to create a database, we can use the command,

use <database_name>. If the given database exists, this command will direct you to that database, else it will create that database for you.

If you have "Saksham" database already, you will get that database. If not, it will create it for you. Now let me give you a surprise. You have created a new database. So it should be listed when you run show dbs command. I want you to try.

use country;

I have created a new database named "country". If I now run the command show dbs. This is what I will get,

Haha, we have no database named "country". Although we created a database, it is an empty database. If we want it to be shown in the above list, we have to add at least 1 collection. Then we will be able to see it in the list of the databases. So first, let's learn how to create a collection.

CREATING COLLECTIONS

To create a collection, you need to run the command:

db.createCollection("<collection_Name>"). This command will let you create a collection of desired names. Let's also create a collection named "states" in our "country" database.

db.createCollection("states");

If you now list the databases, you will see the entry "country" in it. Let's try this.

This time, you can see the entry of the database "country". After creating the collection, let's see how can we list our collections.

LISTING COLLECTIONS

For listing out all the collections of the database, we can run the command:

show collections. Let's try this on the database "country".

Here we go. We can see the collection "states".

Ok so now, let's summarize the article till here. Till now, we have discussed,

HOW TO:

  1. LIST THE DATABASES show dbs

  2. USE OR CREATE A DATABASE use <databaseName>

  3. CREATE A COLLECTION db.createCollection("<collection_Name">)

  4. LIST THE COLLECTIONS show collections

Now comes the most awaited and interesting part. The query for inserting our data into the collections.

INSERTING DATA

As I told you earlier, we store data in a JSON-like format. Let's see how we can. The entry we want to insert in a Collection is called a Document.

Command is: db.<collection_name>.insertOne({key1:value1, key2:value2, ......}). Okay, so we have a collection named "state". Let's make some entries in it.

db.states.insertOne({
name:"Delhi",
region:"North",
weather:"Hot",
population:"High"}
);

As I mentioned earlier, unlike MySQL, where the structure of the table is defined, here in the same collection(like tables in MySQL), we have documents(like rows in MySQL) with different key: value pairs.

Okay let me insert another document,

db.states.insertOne({
   name:"haryan",
   region:"North",
   districts:"1000"}
)

In this entry, we have the key name "districts", still we are successfully able to insert this entry. Now, how do we list the DOCUMENTS we have inserted.

LISTING DOCUMENTS

Command is: db.<collection_Name>.find().

You can see that both the entries are added.

ADDING MULTITPLE DOCUMENTS

Let us say we want to add multiple documents to the database country at once, then the syntax for that will be,

db.collectionName.insertMany([{
name:"Delhi",
region:"Central",
weather:"Hot",
},
{
name:"Haryana",
region:"North",
weather:"Hot",
},
{
name:"Kashmir",
region:"North",
weather:"Cold",
},
{
name:"Sikkim",
region:"North-east",
weather:"Rainy and Cold",
},
{
name:"Kerala",
region:"South",
weather:"Hot and Humid",
}
]);

One important question, that might arise in your mind is, can we store an array in the Document? Yes, you can. Let us see the syntax.

Adding Array in the Document

db.states.insertOne({
name:"Uttrakhand",
weather:"Hot and Cold",
touristPlaces:["IIT Roorkee","Masoorie","Dehradun",]
}
);

Sorry for the spelling mistake in the image. But it must be clear that, yes we can store an array inside the document.

Now to explore different commands in MongoDB we need some sample data. Now I will tell you, how to import the sample data. You can find some sampledata.json files online.

IMPORTING DATA THROUGH MongoDB compass

Create a new database of your choice and make a collection inside it.

Now open the database and click on the ADD DATA button.

A dropdown will appear. Click on the Import file option.

This window will appear. First, select the type of the file you have downloaded. In our case, we are downloading a .json file. Select JSON and then select the file from your system and then click on the IMPORT button.

If you do not have MongoDB compass, don't worry. We can also import data from the command line.

IMPORTING DATA FROM THE COMMAND LINE

mongoimport --db db_name --collection_name --file

This command you have to run in the directory where you have downloaded your sampledata.json.

I think now you are ready to learn more advanced commands of MongoDB, till now we have learned basic commands and also have sample data, to work on.

NUMBER OF DOCUMENTS

The command for finding several Documents inside a collection:

db.collection_name.find().count()

Let me also show you the actual run of the command,

To see the content of the documents inside the collection, we need to run the command db.collection_name.find(), but as our collection contains 10000 documents, the MongoDB shell will not print all the documents instead it will print only limited entries. Also, it will give us a prompt that,

Type "it" for more, if you type it then it will print the next set of documents.

I will show you,

HOW TO LIMIT THE NUMBER OF DOCUMENTS

Suppose we want only (n) number of entries, then we can use the following command,

db.collection_name.find().limit(n)

This command will give you the first (n) documents from your collection.

Now, we may want (n) number of entries but not from the start instead after an offset, we can use the following command,

db.collection_name.find().skip(offset_value).limit(n)

Now suppose, you want to filter data according to the particular [key: value] pair.

FILTERING THE DATA

For filtering the data, we can use the following commands:

db.collection_name.find({key1:value1,key2:value2....})

The above command will provide us with those documents, where the values of key1 and key2 are "value1" and "value2" respectively.

Now suppose, after filtering you do not want all key-value pairs, but only a=want some, then we can use this command,

db.collection_name.find({key1:value1,key2:value2...},
{key1:true},{key2:true}...)

Here both the "key1" are not essentially the same. They just resemble any key name. This will first match the key-value pair and then only provide the "key1" and "key2" of those documents. The important thing to note is, if we don't want to apply a filter, but want all Documents with certain keys, then the syntax is:

db.collection_name.find({},{key1:true,key2:true.....})

Thus it is necessary to pass an empty object. In case we will use false instead of true we will get all the keys except those with false.

Now let us learn how we can delete the data.

DELETING THE DOCUMENTS

Let us see the commands for deleting the documents,

db.collection_name.delteOne({condition1:value1,condition2:value2...})

This command will delete the first document that has the same key-value pair as given in the filter.

For deleting all the documents corresponding to the filter, we can use the command,

db.collection_name.deleteMany({condition1:value1,condition2:value2...})

So till now, we have learned to read the document, write the document, and delete the document. Now we will learn how to update the document.

UPDATING A DOCUMENT

We will now see commands for updating the Documents. Don't worry, they are also similar to the commands earlier.

db.collection_name.updateOne({filter1:value1,filter2:value2...},
{$set:{key1:value1,key2:value2.....}})

This command will update the first document which is according to the filter.

If we want to update all the documents, which are satisfying the filter, we can use the command,

db.collection_name.updateMany(<filter>,
{$set:{key1:value1,key2:value2..}})

As we will move further, the commands will become more interesting. Now we shall see the command for getting all the unique values of a particular key in the whole collection.

LISTING ALL THE UNIQUE VALUES

The command is as follows:

db.collection_name.distinct("keyname")

Let me show you a practical example. I have a sample database in which I have a collection named "weather_data". The documents in the collection have a key named "elevation". Let us see, how many unique values of keys exist in the collection.

Here we can see that elevation only has 1 value. Let's try on other keys also. This collection also has a key named "callLetters".

Here you can see, we have many unique values.

OPERATORS IN MongoDB

MongoDB provides us with operators like comparison, bitwise etc operators.

To use these operators, we can not directly pass the key-value pairs into the filter. Rather we use the following syntax,

db.weather_data.find(property:{$operator:value_tocompare});

COMMONLY USED OPERATORS IN MongoDB

1. $ne --> not equals.

2. $eq --> equals

3. $lt --> less than

4. $lte --> less than or equals

5. $gt ---> greater than

6. $gte ---> greater than or equal to

7. $and --> logical and operation

8. $or ---> logical or operation

9. $not ---> logical not

10. $nor --> logical nor

11. $in --> for checking in the array

12. $nin ---> not in a array

Let's use $ne operator,

Here we are counting the number of documents in which the value of wind.type is not equal to "N". As wind is itself an object, we have to write it like a string.

Now let's use $eq operator.

Now, let us use the $and operator.

We have a different syntax for the and operator. Let us discuss the syntax.

db.collection_name.find({$and:[{filter1:value1},
{filter2:value2},{filter3:value3}..]})

Let's also implement this command,

Now let us use the $in operator.

db.collection_name.find({property:{$in:[...arr]}});

Let's implement this also,

If you want to filter the documents based on a property, whose value can be equal to either of the values in an array. In this case, we can use $in operator.

INFORMATION ABOUT QUERY

When we execute a command, It has a certain execution process, execution duration and other details. To get these details for a particular query, we can run the command, query.explain().

query.explain('executionStats')

Response is:

{
  explainVersion: '2',
  queryPlanner: {
    namespace: 'students.details',
    indexFilterSet: false,
    parsedQuery: {},
    queryHash: 'E475932B',
    planCacheKey: '1DC959E3',
    maxIndexedOrSolutionsReached: false,
    maxIndexedAndSolutionsReached: false,
    maxScansToExplodeReached: false,
    winningPlan: {
      queryPlan: {
        stage: 'COLLSCAN',
        planNodeId: 1,
        filter: {},
        direction: 'forward'
      },
      slotBasedPlan: {
        slots: '$$RESULT=s4 env: { s1 = TimeZoneDatabase(Africa/Accra...America/Indiana/Marengo) (timeZoneDB), s2 = Nothing (SEARCH_META), s3 = 1696887541872 (NOW) }',
        stages: '[1] scan s4 s5 none none none none lowPriority [] @"fcf3d36c-528b-430f-be01-b97394656342" true false '
      }
    },
    rejectedPlans: []
  },
  executionStats: {
    executionSuccess: true,
    nReturned: 4,
    executionTimeMillis: 0,
    totalKeysExamined: 0,
    totalDocsExamined: 4,
    executionStages: {
      stage: 'scan',
      planNodeId: 1,
      nReturned: 4,
      executionTimeMillisEstimate: 0,
      opens: 1,
      closes: 1,
      saveState: 0,
      restoreState: 0,
      isEOF: 1,
      numReads: 4,
      recordSlot: 4,
      recordIdSlot: 5,
      fields: [],
      outputSlots: []
    }
  },
  command: { find: 'details', filter: {}, '$db': 'students' },
  serverInfo: {
    host: 'techsavvy-IdeaPad-5-Pro-14ACN6',
    port: 27017,
    version: '7.0.2',
    gitVersion: '02b3c655e1302209ef046da6ba3ef6749dd0b62a'
  },
  serverParameters: {
    internalQueryFacetBufferSizeBytes: 104857600,
    internalQueryFacetMaxOutputDocSizeBytes: 104857600,
    internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
    internalDocumentSourceGroupMaxMemoryBytes: 104857600,
    internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
    internalQueryProhibitBlockingMergeOnMongoS: 0,
    internalQueryMaxAddToSetBytes: 104857600,
    internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600,
    internalQueryFrameworkControl: 'trySbeEngine'
  },
  ok: 1
}

Hence we can see, that we have so much information about the processing of Query.

The problem now is, suppose we have a large number of documents, and I want to filter them. This will be done by traversing through the whole collection.

Here comes the concept of Indexing.

INDEXING

Indexing is a mechanism by which a database stores data in more data structures to make the searches faster. It reduces the execution time of the queries.

Let us see, how can we create indexes.

db.collection_name.createIndex({property:index});

Let us find those documents where callLetters = "VCSZ".

db.weather_data.find({callLetters:"VCSZ"}).count()

To find the execution stats of the above query, run the command,

db.weather_data.find({callLetters:"VCSZ"}).count().explain("executionStats");
weeather> db.weather_data.find({callLetters:"VCSZ"}).explain("executionStats");
{
  explainVersion: '2',
  queryPlanner: {
    namespace: 'weeather.weather_data',
    indexFilterSet: false,
    parsedQuery: { callLetters: { '$eq': 'VCSZ' } },
    queryHash: '83DD7F46',
    planCacheKey: '9E04CD08',
    maxIndexedOrSolutionsReached: false,
    maxIndexedAndSolutionsReached: false,
    maxScansToExplodeReached: false,
    winningPlan: {
      queryPlan: {
        stage: 'COLLSCAN',
        planNodeId: 1,
        filter: { callLetters: { '$eq': 'VCSZ' } },
        direction: 'forward'
      },
      slotBasedPlan: {
        slots: '$$RESULT=s5 env: { s7 = "VCSZ", s2 = Nothing (SEARCH_META), s3 = 1696924623520 (NOW), s1 = TimeZoneDatabase(Africa/Accra...America/Indiana/Marengo) (timeZoneDB) }',
        stages: '[1] filter {traverseF(s4, lambda(l1.0) { ((l1.0 == s7) ?: false) }, false)} \n' +
          '[1] scan s5 s6 none none none none lowPriority [s4 = callLetters] @"3489155e-bebf-4c13-bfb6-01a8b0d59ec8" true false '
      }
    },
    rejectedPlans: []
  },
  executionStats: {
    executionSuccess: true,
    nReturned: 12,
    executionTimeMillis: 4,
    totalKeysExamined: 0,
    totalDocsExamined: 10000,
    executionStages: {explainded
      stage: 'filter',
      planNodeId: 1,
      nReturned: 12,
      executionTimeMillisEstimate: 4,
      opens: 1,
      closes: 1,
      saveState: 10,
      restoreState: 10,
      isEOF: 1,
      numTested: 10000,
      filter: 'traverseF(s4, lambda(l1.0) { ((l1.0 == s7) ?: false) }, false) ',
      inputStage: {
        stage: 'scan',
        planNodeId: 1,
        nReturned: 10000,
        executionTimeMillisEstimate: 4,
        opens: 1,
        closes: 1,
        saveState: 10,
        restoreState: 10,
        isEOF: 1,
        numReads: 10000,
        recordSlot: 5,
        recordIdSlot: 6,
        fields: [ 'callLetters' ],
        outputSlots: [ Long("4") ]
      }
    }
  },
  command: {
    find: 'weather_data',
    filter: { callLetters: 'VCSZ' },
    '$db': 'weeather'
  },
  serverInfo: {
    host: 'techsavvy-IdeaPad-5-Pro-14ACN6',
    port: 27017,
    version: '7.0.2',
    gitVersion: '02b3c655e1302209ef046da6ba3ef6749dd0b62a'
  },
  serverParameters: {
    internalQueryFacetBufferSizeBytes: 104857600,
    internalQueryFacetMaxOutputDocSizeBytes: 104857600,
    internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
    internalDocumentSourceGroupMaxMemoryBytes: 104857600,
    internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
    internalQueryProhibitBlockingMergeOnMongoS: 0,
    internalQueryMaxAddToSetBytes: 104857600,
    internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600,
    internalQueryFrameworkControl: 'trySbeEngine'
  },
  ok: 1
}

We can see that in the stats, 12 documents met our filter, but to find those 12 documents, it has to traverse through the whole collection. This task took 4ms to be executed. Now let us see how indexing helps us.

db.weather_data.createIndex({callLetters:"text"})

Now, I will run again the same query and then check the "executionStats".

As in this case, the index type is a string, we use a different method to search.

db.weather_data.find($text:{$search:"VCSZ").count().explain("executionStats");

For this command, you will see that the execution time is 0ms, and it also doesn't traverse through the whole collection.

Ok so now let's wrap up the article here. I have explained almost all the major commands in MongoDB.

Happy Coding!

Did you find this article valuable?

Support WEB DEVOLOPMENT by becoming a sponsor. Any amount is appreciated!