Forgot Your Password?

Choose Your Plan

Start Building Real Apps

Pay Monthly

12

Pay Yearly

10
2 months free
Top shelf web developer training.

Guided Paths

Follow our crafted routes to reach your goals.

Courses

Premium content to build real apps.

Code Tutorials

Examples to follow and learn from.

Getting Started with MongoDB on Linux

Quite recently, I decided to jump ship to Mongodb after years of web development using MySQL database. The one thing that attracted me the most to Mongodb is that you can start pushing data to the database without first defining a schema. This means you can spend more time iterating app code without lifting a finger managing the database schema.

Mongodb is a very mature platform with about 10 years in development and is being used by big name companies that handle data for millions of customers everyday. It has a huge community behind it and is currently ranked fourth as the most popular database.

This post is an extended getting start guide for Ubuntu & Linux Mint users on how to properly set up a secure Mongodb server and how to solve common configuration issues. The information provided here is as a result of knowledge gained through researching the official doc guides and experimenting to validate the concepts learned.

I've provided this knowledge here to make it easy for beginners to transition to the Mongo database on the Linux platform.

1) Installing Mongodb

Before installing Mongodb, make sure you have purged all previous versions of mongodb. The mongodb version that is currently available in the official ubuntu repositories is outdated and has an issue where large amounts of disk space are consumed by its journal. To purge the outdated version, just execute the following:

sudo apt-get purge mongo*
sudo rm -R /var/lib/mongo

Next, you'll need to add the official mongodb repository that contains the latest community version.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6

# For Ubuntu Xenial or Linux Mint 18.*
echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list

# For Ubuntu Trusty or Linux Mint 17.*
echo "deb [ arch=amd64  or Linux Mint 17] http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list

# For Ubuntu Precise or Linux Mint 13
echo "deb [ arch=amd64 ] http://repo.mongodb.org/apt/ubuntu precise/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list

sudo apt-get update

Once the repository cache is updated, run the install command:

sudo apt-get install -y mongodb-org

Ensure you typed mongodb-org, and not mongodb, otherwise you'll install the old version.

2) Auto-starting Mongodb Service

The next obvious step after finishing installation is to start the mongo shell, right?

Mongo shell

Unfortunately, you will encounter connection errors. This is because Mongodb does not start automatically on boot or after installation. To fix this, run the following commands that will start the mongodb service and enable it to auto-start on boot.

sudo systemctl start mongod
sudo systemctl enable mongod

To confirm that mongodb server has successfully started, execute either of the following commands:

# Check ports in use
netstat -plntu | grep 27017

// Check service status
sudo service mongod status

27017 is the default port used by Mongodb server to listen for connections. I prefer the second command for checking status as it displays more information such as if its enabled to run on boot and if there are errors in its configuration file if they are any.

3) Basic Performance Tuning

Now that the Mongodb service is running, you can now use mongo shell to access the server by executing mongo in the terminal.

Mongo shell warnings

The mongo shell starts successfully, however, you get hit by several warning messages. Despite the warnings, you can create new databases and add documents to the collections. However, I recommend that we first resolve the warning messages.

Let's start with these warning messages that are in regards to performance:

** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
**        We suggest setting it to 'never'

** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
 **        We suggest setting it to 'never'

According to the official docs, Mongo recommends that you disable a Linux Memory Management feature called Transparent Huge Pages as it causes databases workloads to perform poorly.

To fix this, create a new file at /etc/init.d/disable-transparent-hugepages and paste this content. After saving the file, execute the following commands:

sudo chmod 755 /etc/init.d/disable-transparent-hugepages
sudo update-rc.d disable-transparent-hugepages defaults

Since the above commands affect the Linux kernel, you'll have to restart the entire machine for the changes to take effect.

After restarting the machine, simply type mongo and you should connect to the mongodb server. The shell no longer displays the warning messages regarding the 'transparent-hugepages.

However, there are two more warnings that still need to be solved which we shall look at in the next step.

4) Basic Mongodb Security

By default, mongodb is insecure. The reason for this, I believe, is to make it easy for new users to try out Mongodb comfortably, and hence increase adoption. Security is left at the hands of the users to implement when they are ready.

When you access the mongo shell like this...

mongo

...you get logged in as default user. In this account you are free to perform any CRUD operation you feel like provided authentication hasn't been set up. Lets try some basic commands in the mongo shell to confirm this:

// switch to a new database
use twist

// insert a document to a new collection called 'users'
db.users.insert({name:"mike", email:"mike@example.com"})

// list all documents in the newly created collection
db.users.find()

All the above operations should execute with no problem whatsoever. Now lets proceed with securing our mongodb server in order to protect our data from anonymous users.

First, we need to turn on the 'auth' setting for mongodb. There are several ways of doing it, but the method I prefer is by editing the /etc/mongod.conf file.

Using administrative privileges, edit the file /etc/mongod.conf using your favorite text editor:

# using console editor
sudo nano /etc/mongod.conf

# using Ubuntu text editor
sudo pluma /etc/mongod.conf

# using Linux Mint text editor
sudo xed /etc/mongod.conf

Look for the commented out section called security and edit as follows:

security:
    authorization: enabled

Save the changes above, close the file and restart mongodb service for the changes to take effect.

# restart mongodb server
sudo service mongod restart

# confirm mongodb service is running
sudo service mongod status

# log in as default user
mongo

You'll notice that the remaining warning messages have now disappeared. Mongodb is now running in auth mode, therefore the 'access control' warning should disappear. The 'XFS file system' warning too also disappears mysteriously after enabling authentication. Currently, I don't know why this happens. However, I'll be sure to use XFS file system when installing Mongodb in production servers since it comes highly recommended.

Let's now confirm that default users can't read or write to any database. Inside the mongo shell, execute the following:

use twist
db.users.insert({name:"maggie", email:"maggie@example.com"})

As expected, the default user is prevented from accessing documents from any collection. Now we can proceed with creating an authenticated user.

The way authentication works in Mongodb is that you need to save user accounts in a special database called admin. Within this database you will need to create an admin user who will be responsible for creating new user accounts and assigning roles.

As an admin user, you can create more users within the admin database, or you can switch to a new database and create them there. However, during login authentication, you will have to specify which database is holding the user credentials you want to login.

As demonstrated earlier, the default user currently has no privileges. However, since no users have been created, an exemption will be made to allow the default user to create an admin user.

// switch to the admin database
use admin

// create a new user to be stored in the admin database
db.createUser({ 
    user:"admin", 
    pwd:"abc123", 
    roles:[
        { role: "userAdminAnyDatabase", db: "admin"  }
    ] 
})

// log out of mongo shell
exit

After the admin user has been created, the default user account won't be allowed again to create any user.

To log in as the admin user, do...

mongo -u admin --authenticationDatabase admin -p

... you will be prompted to enter the password for the newly created admin user. The flag --authenticationDatabase is used to pass the name of the database holding user credentials.

As the new mongodb admin, you can now create new users for other databases. Let's create one for the database twist:

// ensure the new user is created under admin
use admin

// create new user and assign Read/Write permission only
db.createUser({ 
    user:"twister", 
    pwd:"xyz123",
    roles:[{ role: "readWrite", db: "twist"  }]  
})

Exit the mongo shell and now login back with the new user credentials within the shell.

 mongo -u twister --authenticationDatabase admin -p

Enter the password as prompted. Next, switch to the twist database and add some data.

// switch to the twist database
use twist

// display all collections
show collections

// insert a new record
db.users.insert({name:"maggie", email:"maggie@example.com"})

// display all records
db.users.find()

As expected you now have access to read and write capability in the twist database. As a simple exercise, try switching to another database, say library and try adding documents and see what happens.

As expected you will get authorization errors informing you that you lack the permission to perform the operation.

If you would like to update a user account, say change password, you normally have to logout and login as the admin user to be able to do that. Alternatively, you can do this while still logged in as another user:

// Switch to the admin database
use admin

// Login as the admin user
db.auth("admin","abc123")

// Change the user password
db.updateUser(
    "twister",
    {
        pwd: "zyx123"
     }
)
exit

You will need to exit the mongo shell in order for the password change to take effect. You can now log in back again using either mongo shell parameters or log in as default user then use db.auth() function to login as 'twister'. When using db.auth() function, make sure you switch to the admin database first since this is where the user accounts are stored. When it returns '1', it means you are authenticated and you can now switch to the twist database to perform some data manipulation.

So far you have learned how to secure your Mongodb server. You can go over the official security checklist if you want to further enhance your database security.

5) Mongo CRUD Operations

So far, I have shown you how to insert data. Here are other common operations that you need to learn.

Insert Documents

Lets first create a new collection with data that we shall manipulate with using other operations. But before we get started, here are some naming conventions suggested for Mongodb collections:

  • Use lower case names
  • Use plural
  • Avoid word separators such as '-' or '_'
  • Use dot notation to indicate relation e.g.
    • users
    • users.pagevisits

Lets now create a collection called pets and populate it with data. Below you will see the different ways of inserting data into a collection.

// Insert single document
db.pets.insert({name:"Fluffy", owner:"Harold", speices:"cat", sex:"F",birth:"2013-02-04"})

// insertOne() returns the object id
db.pets.insertOne({name:"Claws", owner:"Gwen", speices:"cat", sex:"M",birth:"2014-03-17"})

// Insert an array of documents
db.pets.insert([
    {name:"Buffy", owner:"Harold", speices:"dog", sex:"F",birth:"2009-05-13"},
    {name:"Fang", owner:"Benny", speices:"dog", sex:"M",birth:"2010-08-27"},
    {name:"Bowser", owner:"Diane", speices:"dog", sex:"M",birth:"2014-08-31"}
])

// insertMany() returns array of objectIds
db.pets.insertMany([
    {name:"Chirpy", owner:"Gwen", speices:"bird", sex:"F",birth:"2009-09-11"},
    {name:"Whistler", owner:"Gwen", speices:"bird", sex:"M",birth:"2007-12-09"},
    {name:"Slim", owner:"Benny", speices:"snake", sex:"M",birth:"2016-04-29"}
])

// display all rows
db.pets.find()

// returns number of rows (should be 8 if you executed all of the above)
db.pets.find().count()

Query

Executing queries in mongodb is fairly simple. If you are familiar with SQL, then you'll understand the following operations.

// list all documents a.k.a select * from pets
db.pets.find()

// list all pets owned by Gwen
db.pets.find({owner:"Gwen"})

// lists all male pets
db.pets.find({sex:"M"})

// list all male dogs
db.pets.find({sex:"M", speices:"dog"})

// list pets that are either female cats or birds
db.pets.find({ 
    $or: [ 
        {speices:"cat", sex:"F"}, 
        {speices:"bird"}
    ]  
} )

// list all pets born on the year 2010 and later
db.pets.find({ 
    birth: { $gt:"2010-01-01" } 
})

Update Documents

Now that there is some data to manipulate, lets do an update operation

db.pets.update(
    { name: "Slim"},
    {
        $set: { owner: "Ben", speices:"Lizard"}
    }
)

// display all rows
db.pets.find()

In the above update() function, I have provided 2 parameters

  • filter (similar to WHERE clause)
  • update data

You can also provide a third parameter called options. Examples of options are:

  • { multi:true } allows update operation to affect more than one matching rows
  • { upsert:true} if the filter specified doesn't match a document, a new document is created

There are more variations of the update() function you can have a look at them here

Remove Documents

Let's first create a new collection for demonstration

db.jets.insert({name:"Lockheed Martin F-22"})

The remove() function, just like the SQL 'DELETE' command, is a dangerous function that should be handled with care. Simply executing something like this...

db.jets.remove({})

... will delete all documents in a collection. Once a document is deleted, it doesn't go to trash, it goes away forever. There is no undo operation or rollback function you can use to recover the deleted data. If you did this accidentally on a production database, the ramifications can be pretty serious. This happened at work to a colleague of mine. Luckily he was able to restore the data from the daily backups.

However, if you really wanted to delete all documents from a collection, this is the recommended way

// display all collections first
show collections

// drop jets collection
db.jets.drop()

// display all collections again
show collections

By using drop() function, the indexes get deleted too and completely gets rid of the collection. Using just remove({}) will just delete the documents and retain the indexes, hence the collection will still exist despite not containing any data.

Now , let's delete a single document from the pets collection

// Lets display all pets
db.pets.find()

// Delete one document
db.pets.remove({name:"Bowser"})

// Confirm the specified document has been deleted
db.pets.find()

The remove() function works as expected, however, its still risky as it will delete all documents matching the filter. A better way is to use the deleteOne() function and pass it the _id value of a document. This way you will be 100% sure that you are deleting the correct document.

// Display the pets again and copy an object id
db.pets.find()

// Delete one document
db.pets.deleteOne({_id:ObjectId("58b51bfb54deb7f848d5310a")})

// Confirm it has been deleted
db.pets.find()

6) Administration GUI

Mongodb doesn't come packaged with a GUI administration interface, however there are plenty of third-party GUI interfaces available. Some are commercial, and some are open-source. They are all listed on the Mongo docs site. They don't all provide the same features, you may have to dig a bit deeper to determine if the tool meets your project requirements.

I can't say for sure which is the most popular Mongo GUI tool available, but I have found that RoboMongo and Studio-3T(formerly MongoChef) seem to be the most popular. Personally, I would recommend Studio-3T as it does appear to provide all features available in RoboMongo plus a lot more including user administration. Studio-3T also comes in three flavours, you can view the comparison here.

For this guide I'll just show you how to install Studio-3T. Head over to the site and click the Download for Linux button. After download is complete, use the extraction tool to uncompress it in your Downloads folder.

Uncompress Studio-3T

Open your terminal and navigate to your downloads folder. Move the robomongo folder to the /opt folder. You'll probably need root permission to do that.

# move studio-3t to /opt folder
sudo mv studio-3t-5.0.1-linux-x64/ /opt/studio3t/

# download icon
cd /opt/studio-3t
sudo wget http://cdn-web.3t.io/wp-content/uploads/logo_pro_256.png

# make studio-3t executable available in PATH
cd /usr/bin
sudo ln -s /opt/studio3t/bin/studio-3t.sh studio3t

Let's create a menu entry for Studio-3T using the menu editor. Just place your mouse cursor over the your Desktop Menu and right-click, select Edit Menus. Then select Programming. Click on new item and enter the path to Studio-3t executable. Also select the icon that we downloaded in the /opt/studio3t folder.

Studio-3T Menu Entry

Now that we have finished installing, lets start the application. You can either start it from the menu or in the terminal. Once the app starts, you will be given three options. You can choose either the free version or the 14 day pro trial.

After you have chosen you will be provided with the connection dialogue.

Studio-3T Connection Dialogue

Let's first create a connection for the admin user, then the twister user. Click New Connection, specify 'Admin' as the name of connection. Make sure sure connection type is set to 'Direct Connection'. Click the Authentication Tab, under mode select Basic, then provide the admin credentials. For the authentication DB, set it to 'admin'. Click save to close the dialogue.

Studio-3T New Connection

To create a connection for the user 'twister', just repeat the same steps. The authentication DB will remain 'admin'. When you connect as a certain user, Studio-3T will only show you databases that you have access to. After you have saved the new connection, you can go ahead and connect to both 'Admin' and 'Twist'.

Studio-3T Interface

As you can see, the Admin user can see all the databases but the Twist user can only see admin & twist database. Although the Admin user can see twist database, the collections are not accessible. Let's see if we can correct this.

Right click on the admin database under Admin connection, then choose manage users. Select the admin user, then click on Grant Roles Button. Choose 'readWriteAnyDatabase' then click Grant.

Studio-3T Grant Roles

Right click on th Admin connection and select Refresh All. Now under the Admin connection, access pets data.

Studio-3T View Collection

Studio 3T has quite a list of features that are beyond the scope of this guide. I'll leave you to it exploring both Mongodb and the Studio 3T tool.

Conclusion

I hope you have enjoyed learning how to setup and configure a secure Mongodb database. You have simply scratched the surface of the many possibilities and great projects you can come up with this awesome database platform. Despite what you have learned today, you will still need to do a bit more research on how to become an effective Mongodb user.

Michael Wanyoike

I like keeping it simple. I write clean, readable and modular code. I love learning new technologies that bring efficiencies and increased productivity to my workflow. Currently am into React & Javascript stuff.