How To Setup MongoDB Like a Pro
Tags: webdev, mongodb, database, tutorial
Published: 2024-01-24 07:46:28

##Introduction

I started my career 6 years ago as a Frontend Engineer. We had mongoDB as our main database. Although I was a FE, I have  always been fascinated by how the fancier things like replication, caching actually works. I was too afraid to try it, hoping I would break the running things on my system and would have to spend a lot of time fixing that. The fear stopped me from trying a lot of things I wanted to try. Today we will be trying one of those things and break the shackles. 

We will be going through setting up mongoDB on your local machine and running multiple instance of it to setup replicaSet and how to add new machines and remove machine and all that, this skill can be directly transffered to a cloud based setup as well. 

##Installing MongoDB(community edition - 6.0)

Installing MongoDB DB can be varied based on your local machine. You can follow the steps below if you are using Ubuntu 22.04 otherwise you can follow this guide [here](https://www.mongodb.com/docs/v6.0/administration/install-community/).

MongoDB only supports the 64-bit versions of these platforms. To determine which Ubuntu release your host is running, run the following command on the host's terminal:
```bash
cat /etc/lsb-release
```

- Import the public key used by the package management system
```bash
# install gnupg and curl if they are not already available
sudo apt-get install gnupg curl

# import the MongoDB public GPG key
curl -fsSL https://pgp.mongodb.com/server-6.0.asc | \
   sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg \
   --dearmor
```

- Create a list file for MongoDB
```bash
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
```

- Reload local package database
```bash
sudo apt-get update
```

- Install the MongoDB Package
```bash
sudo apt-get install -y mongodb-org
```

If there was no error, you would have successfully installed mongod and mongosh CLI Tools.

I ran into some issues, I will mention the StackOverflow links here which helped me with the issues:

- [Unable to locate package mongodb-org](https://stackoverflow.com/questions/28945921/e-unable-to-locate-package-mongodb-org)
  - You can try to install the package, mongodb instead of monggodb-org. It is the unofficially package.
  - I was installing the version 7 which is the latest, but I chose to used the previous version and the issue was solved.

---

## Getting comfortable with `mongod` and `mongosh`

If you are running a Mac, you'll most likely be using brew to install all the background services and running them. You can use the similar commands in Ubuntu as well using systemd to run the services in daemon mode or in background.

###Starting the service

```bash
sudo systemctl start mongod
```

This should start the `mongod` on port 27017, If you run into any issues, you'll have to debug the issue.

###Stopping the service

```bash
sudo systemctl stop mongod
```

###Restarting the service

```bash
sudo systemctl restart mongod
```

###Connecting to a `mongod` instance with `mongosh`

```bash
mongosh
```

You'll be taken into the shell and you'll be connected to test db by default and you can experiment all you want with it.

---

## Running `mongod` in foreground

You can run mongod on the foreground as well. No matter where you run it from background or foreground, it knows where to store the data, it knows where to write the logs, it knows what port to start on. How does it know? The secret is `/etc/mongod.conf` file.

Now if you cat /etc/mongod.conf file, you'll get something like this:

```
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
#  engine:
#  wiredTiger:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1


# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

#security:

#operationProfiling:

#replication:

#sharding:

## Enterprise-Only Options:

#auditLog:

#snmp:
```

For the beginners, there are 2 important things mentioned in this file: 

- storage.dbPath
- net.port

####storage.dbPath
It refers to a directory, where mongo will be storing all the data.

####net.port
It refers to a port, on which the mongod will start.

---

It is because of this conf file, you can't start multiple mongod instance. You can try starting two mongod instances on two terminal windows and it'll give a port error, mentioning the port is already occupied.

The good thing is now we know what are the keys and we have an option to overwrite these keys with our values. Lets explore that option.

---

##Starting `mongosh` with different arguments

When you start mongod, it picks the default port from /etc/mongod.conf file, which is 27017. In order to start the mongod on a different port, either you can update the mongod.conf file to use a different port or you can provide command line argument like this:

```bash
mongod --port 27019
```

Running this command you'll be able to start the mongod on port 27019.

> Keep in mind to connect to this instance using mongosh, you'll need to pass the port as well using --port

It also picks up a default location of the db. You can pass in the `dbPath` to override that as well. Before we do that lets make a directory call mongo-dbs and create db1, db2 and db3 directory inside of it and start 3 different instance of mongo on different ports and dbs separate from each other.

```bash
mkdir mongo-dbs
cd mongo-dbs
mkdir db1
mkdir db2
mkdir db3
```

Now in the first terminal, type in:

```bash
mongod --dbpath ./db1 --port 27020
```

In the second terminal type in:

```bash
mongod --dbpath ./db2 --port 27021
```

In the third terminal, type in:

```bash
mongod --dbpath ./db3 --port 27022
```

Now you have three different instances of mongod running, you can connect to each of them using mongosh --port <PORT>.

---

##Replication

If you have made it this far in the blog, congratulations. Lets see how the replication works in mongodb and setup a master - slave - slave replication.

If you see the mongod.conf file, you'll see:

```bash
#replication:
```

That means by default the mongod doesn't have any replication setup.

Inorder to setup mongod as replicas, we need to start it in a replication mode and give the replica a name. You can do that by:

```bash
mongod --dbpath ./db1 --port 27020 --replSet my_replica
```

And you can start the other instances as well in the same manner keeping the name my_replica consistent.

Once all the instances are running choose which mongod you want as primary and log on to that instance with mongosh --port <PORT>.

Now type in the command to initiate the replication:

```bash
rs.initiate()
```

This should give an acknowledgement that the replication has been started. In order check the status of the replicaSet:

```
rs.status()
```

It throw out something like this:

```
{
  set: 'myreplica',
  date: ISODate('2024-01-24T07:07:53.872Z'),
  myState: 1,
  term: Long('6'),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {...},
  lastStableRecoveryTimestamp: Timestamp({ t: 1706080036, i: 1 }),
  electionCandidateMetrics: {...},
  electionParticipantMetrics: {...},
  members: [
    {
      _id: 0,
      name: 'localhost:27020',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 2800,
      optime: { ts: Timestamp({ t: 1706080066, i: 1 }), t: Long('6') },
      optimeDate: ISODate('2024-01-24T07:07:46.000Z'),
      lastAppliedWallTime: ISODate('2024-01-24T07:07:46.580Z'),
      lastDurableWallTime: ISODate('2024-01-24T07:07:46.580Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1706078026, i: 1 }),
      electionDate: ISODate('2024-01-24T06:33:46.000Z'),
      configVersion: 5,
      configTerm: 6,
      self: true,
      lastHeartbeatMessage: ''
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1706080066, i: 1 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1706080066, i: 1 })
}

```
If everything has worked for you till now, congratulations. Now we will be adding new members to this replicaSet. To add a new member:

```
rs.add('localhost:27021')
```

This will also give an acknowledgement that a member has been added. Now if you check the status of the replicaSet:

```
rs.status()
```

You have two members marked: 

> stateStr: 'PRIMARY' and the other as stateStr: 'SECONDARY'

Denoting the primary and the secondary instances. Secondary will also have one key

> syncSourceHost: 'localhost:27020'

Denoting which instance it will sync the data from. In the similar fashion, you can add the last instance as a member of this replicaSet and check the status. 

Now if you add any data in the primary member it'll automatically be synced to the secondary members.

---

##Production Setup

We have learned a lot of stuff, and it can be very daunting to try this for the first time. Lets expand this knowledge and move from local to production. 

We replicate data, to increase our availability, so if somehting happens to one instance other instances are running. Replicating data on same machine would mean if something wrong happens to the machine like power outage etc, the whole database would stop responding to requests.

So in production we have multiple machines, and we have update the mongod.conf file on each of the machine to setup replication.

##Things to explore

I want you to explore:
- What happens when you shut off a instance?
- Suppose we have data in the instances already, and you add a blank member, what will happen. 
- What happens when a primary member is not working?