cwarny
cwarny

Reputation: 1007

Setting up mongodb on Heroku with Node

On my local host, I have the following Node code to setup a mongoDB database name "dbname":

users.js:

var MongoClient = require("mongodb").MongoClient,
    Connection = require("mongodb").Connection,
    Server = require("mongodb").Server;

Users = function(host, port) {
  var mongoClient = new MongoClient(new Server(host, port));
  mongoClient.open(function (){});
  this.db = mongoClient.db("dbname");
};

Users.prototype.getCollection = function (callback) {
  this.db.collection("users", function (error, users) {
    if (error) callback(error);
    else callback(null, users);
  });
};

Users.prototype.findAll = function (callback) {
  this.getCollection(function (error, users) {
    if (error) {
      callback(error);
    } else {
      users.find().toArray(function (error, results) {
        if (error) {
          callback(error);
        } else {
          callback(null,results);
        }
      });
    }
  });
}

// Bunch of other prototype functions...

exports.Users = Users;

I like to put the above database functionality in one file, and then in my main server file require that file as follows:

server.js:

var Users = require("./users").Users;
var users = new Users("localhost", 27017);
users.findAll(function (err, user) {
  // Do something
});

To have this working on localhost is pretty easy. In the command line, I just type the following:

$ mongod # to launch the database server
$ node server.js # to launch the web server

and it works fine. However, now I'm trying to push the whole thing onto Heroku with the mongolab addon

heroku addons:add mongolab

but the database is not running and I have no idea how to make it run. This tutorial explains how to setup mongodb with the mongolab URI, but that's not how my code works, I use a host and a port and I create a new server based on that. How should I change my code for it to work on the heroku app? I want to keep the database code in a separate file, with the prototype functions.

Upvotes: 1

Views: 3736

Answers (2)

cwarny
cwarny

Reputation: 1007

Helped by Xinzz's answer, here's the modified code, so that the mongodb database is initialized with a URI instead of host + port. That's how Heroku initializes the mongodb database, and that's why it wasn't working.

var mongodb = require("mongodb");

var MONGODB_URI = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || "mongodb://localhost", // Make sure to replace that URI with the one provided by MongoLab
    db,
    users;

mongodb.MongoClient.connect(MONGODB_URI, function (err, database) {
  if (err) throw err;
  db = database;
  users = db.collection("users");
  accounts = db.collection("accounts");
  var server = app.listen(process.env.PORT || 3000);
  console.log("Express server started on port %s", server.address().port);
});

The key here is to declare the variables db and users upfront, assign them a value in the asynchronous callback of the connect function of MongoClient and also start the app (app.listen(...)) in the same callback. Then later in the code I can do the following:

users.find().toArray(function (err, results) {
  // Do something
});

I also gave up on all these prototype functions, since they did not really add much.

Upvotes: 1

Xinzz
Xinzz

Reputation: 2252

Follow the example here at the "MongoClient.connect" section.

Essentially, you will need to change this part of the code:

Users = function(host, port) {
  var mongoClient = new MongoClient(new Server(host, port));
  mongoClient.open(function (){});
  this.db = mongoClient.db("dbname");
};

To use mongoClient.connect() instead of new MongoClient:

Users = function(url) {
  MongoClient.connect(url, function(err, db) {
    // Find better way to set this since this callback is asynchronous.
    this.db = db;
  });
};

If you are using node, I recommend using a library such as mongoose npm install mongoose to handle mongodb interactions. Look at my answer here for how to structure your schemas.

Upvotes: 2

Related Questions