Search code examples
node.jsmongodbherokumongoosemongodb-atlas

How to connect heroku to MongoDB Atlas


I've been having a complete nightmare, trying to connect my heroku app to MongoDB Atlas, as mLab has now been deleted as a Heroku addon.

The problem I'm having, is that I can't seem to connect my app, to my Atlas DB.

  1. I've created a cluster in Atlas.
  2. Set my cluster IP address to 0.0.0.0/0
  3. Updated my Config Vars in Heroku.

It seems as if my app is working fine locally...

To add some complexity, a couple of years ago, I could run mongoose locally, just by running the mongod command. However, this seems to have stopped working, because of the the MacOS Catalina update.... My terminal couldn't /data/db directory:

MongoDB can't find data directory after upgrading to Mac OS 10.15 (Catalina)

So I followed instructions to create a new /data/db folder. This works locally, if I run: mongod --dbpath=/Users/reenaverma/MongoData

So locally, I can use my app and update the DB fully.

However, when I access my app in PROD/heroku, every time I try to login or perform REST/DB actions, (such as a get request), I get a 503 error. So I know, my DB isn't connected in PROD/heroku.

I'm running out of ideas, as to what I'm missing.

My mongo --version is MongoDB shell version v3.6.2.

Here's how my index.js looks. Any ideas, would be much appreciated!!

const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
const router = require('./config/router');
const session = require('express-session');
const flash = require('express-flash');
const userAuth = require('./lib/userAuth');


const app = express();
const PORT = process.env.PORT || 8000; 

// CONNECT TO THIS DATABASE
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost/music-database', { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.set('useCreateIndex', true);

// SET EJS USE
app.set('view engine', 'ejs');
app.set('views', `${__dirname}/views`);
app.use(expressLayouts);
app.use(express.static(`${__dirname}/public`));


// ENSURES FORM DATA IS LISTENED TO AND CAPTURED
app.use(bodyParser.urlencoded({ extended: true }));
app.use(methodOverride(req => {
  if(req.body && typeof req.body === 'object' && '_method' in req.body) {
    const method = req.body._method;
    delete req.body._method;
    return method;
  }
}));

// SETTING UP SESSION COOKIE
app.use(session({
  secret: 'xxxx(', // a random key used to encrypt the session cookie
  resave: false,
  saveUninitialized: false
}));

// setup flash messages must be AFTER express-session
app.use(flash());

app.use(userAuth);
app.use(router);

// GLOBAL ERROR CATCHER FOR 422 and 500
app.use((err, req, res, next) => {
  if(err.name === 'ValidationError') return res.render('pages/422');
  res.render('pages/500', { err });
  next(err); //display error in terminal/also a callback function
});

// PORT LISTENER - MUST BE AT BOTTOM
app.listen(PORT, () => console.log(`Up and running on port ${PORT}`));

And here's how my Config Vars looks, in Heroku:

enter image description here


Solution

  • I figured out that answer! I realised I was not setting the correct value, to my Config vars key, (My password was not included previously and nor was ?retryWrites=true&w=majority).

    If you're setting Heroku via terminal, your command should look like this:

    heroku config:set MONGODB_URI="mongodb+srv://<YOUR_USERNAME>:<YOUR_PASSWORD>@cluster-popuplondon.i2thd.mongodb.net/<YOUR_DATABASE_NAME>?retryWrites=true&w=majority"

    And this 100% solved the problem.