16

I am using express 3.x and mongoose 3.6.4.

So far I have been creating a mongoose connection in my express apps.js file like this:

var mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1:27017/mytest');

And then I have separated my models into separate files like models/user as follows:

var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;

var userSchema = new Schema({
userId: ObjectId,
givenName:String ...
});

exports.User = mongoose.model('User', userSchema);

And then in multiple routing files, I have used the User model like so:

var User = require('./models/user').User;
User.findById(id, function(err, user){ ...

This has worked well for local development. All of the models share the same connection.

But now I would like to use mongoose.createConnection() and create a connection pool that can be used in a similar manner. I would like to establish a connection pool when the app starts and use the pool for all models. So, I have tried this:

var conn = mongoose.createConnection("localhost","dpatest", 27017,{user:"???",pass:"???"});

But the models don't automatically share the connection. So, I have tried various things such as export the connection and trying to consume it in the models. But nothing has worked other than setting up a separate connection for each model.

Can someone explain how creating a single connection pool can be done using mongoose.createConnection()?

Here's more info on my question:

/************ app.js *****************/
var http = require('http');
var path = require('path');
var express = require('express');
//these are my routing files
var auth = require('./src/auth');
var profile = require('./src/profile');
var admin = require('./src/admin');
var tx = require('./src/tx');
var system = require('./src/system');
var servicing = require('./src/servicing');

var dbUri;
var dbUser = "?????";
var dbPass = "?????";

//here are my configurations for development and production
app.configure('development', function(){
    app.set('port', 3460);
    app.use(express.errorHandler());
    dbUri = "mongodb://mongodb://127.0.0.1:27017/dpatest";
});

app.configure('production', function(){
    app.set('port', 3461);
    dbName = 'dpa';
    dbUri = "mongodb://"+dbUser+":"+dbPass+"@ds052525.mongolab.com:51437/dpa";
});

/*
this is what I was originally using for development
and want to change for deployment
*/
mongoose.connect(dbUri);

This was what I was planning on moving to:

var conn = mongoose.createConnection(dbUri);

My models (5 different models) are in a directory named src/models from the root of the app. For example the user model:

/************ user.js *************/
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var userSchema = new Schema({
    userId: ObjectId,
    givenName: String, ...
});

which was being exported as follows:

exports.User = mongoose.model('User', userSchema);

Then, models are used in the various routing files like so:

/****************auth.js**************/
var User = require('./models/user').User;

exports.createAccount = function(req, res){
    var user = new User({});
    . . . 
    user.save(function(err, usr){

    });
};

I'm looking for a concrete example of how to replace mongoose.connect() with mongoose.createConnection and get it to work accross multiple modules. Sergey's answer looks promising but I don't understand how to reference the model in a routing file. I tried:

var User = require(../models).User

But couldn't get it to work. It keeps throwing a reference error.

Thanks!

rob_hicks
  • 1,734
  • 3
  • 23
  • 35
  • Mongoose connections are already internally backed by a separate pool for you. http://mongoosejs.com/docs/connections.html#connection_pools – aaronheckmann Apr 11 '13 at 21:15
  • every model you add on that connection will use the pool: `conn = mongoose.createConnection(..); var Model = conn.model('Model', new Schema(..));` – aaronheckmann Apr 11 '13 at 21:16
  • Aaron, thanks. I read the doc on connection pools and think I understand it. The problem I am having is defining the db connection in the app.js file and then using that connection in my model definition files (one model per file) and in the routing files. I've tried the global.conn idea that Daniel providedcouldn't get it to work and the separate index.js file that Sergey suggested but couldn't get it work either. Is there an example of an express app that uses createConnection to create one connection that is shared in separate modules? – rob_hicks Apr 11 '13 at 22:22
  • https://github.com/LearnBoost/mongoose/tree/master/examples/connection-sharing – aaronheckmann Apr 11 '13 at 23:36
  • Aaron, thanks. This is exactly what I needed. Daniel had proposed this approach. I finally got it to work doing it in this fashion. Now I'm having other issues. I primarily did this to get gridfs-stream to work. It appears that I can get uploads into the db but now can't get them out. – rob_hicks Apr 12 '13 at 12:30
  • @aaronheckmann The link is dead. Can you update it? – Matthias Max Dec 11 '17 at 09:57
  • This is the new link https://github.com/Automattic/mongoose/tree/master/examples/express/connection-sharing – Chiyaan Suraj Feb 19 '20 at 11:59

4 Answers4

4

in your models folder create index.js

e.g.

    module.exports = function (mongoose,  dbconn) {
        return {

            modelname:  require("./file" )(mongoose, dbconn),
            modelname2:  require("./file2" )(mongoose,  dbconn),
   };
};

then load it in your main startup file file where you create your db connection via

var models    = require("./models")(mongoose,dbconn);

the example model file in the models folder should look something like this:

module.exports = function (mongoose,  dbconn) {
    /*
     * 
     */
    var schema = new mongoose.Schema({
        /**
         * field
         * @type String
         */
        field: String......
      });

  return dbconn.model("modelname", schema, "collectioname");
};

and so on....

Sergey Benner
  • 4,421
  • 2
  • 22
  • 29
  • But then how are the models referenced in the routing files? I tried: var User = require('../models').User but that didn't work. – rob_hicks Apr 11 '13 at 20:57
  • if you have only one model in the index file then you should create a variable like `var models = require('../models')(mongoose,dbconn);` then `var User = models.User;` or in your routes you may pass this parameter (models) to any of your route file/module and so on – Sergey Benner Apr 11 '13 at 21:11
  • Sergey, thanks. I've tried what I believe you suggested but couldn't get it to work. It works up to the routing files, which throw an error when I use var User = require('./models').User. The error is: Cannot call method 'findOneAndUpdate' of undefined. – rob_hicks Apr 11 '13 at 22:24
  • Rob your schema file User should look different -- please refer to my answer how your model file should look like. you should return your Model in this file and pass corresponding connection params in order to create your schema model – Sergey Benner Apr 11 '13 at 23:37
  • Sergey, thanks for your help. I tried to wrap it the entire model in the manner you suggested, so that mongoose is passed in from the index.js file. But when I did I kept getting reference errors for the ObjectId. I think your approach makes sense. – rob_hicks Apr 12 '13 at 12:28
  • You shouldn't set the ObjectId for your user - it's being created automatically. If you want to create a reference to another collection you should use something like this http://mongoosejs.com/docs/populate.html read more about pseudo joins in mongoose – Sergey Benner Apr 12 '13 at 13:28
  • This structure just saved my bacon. Thanks. – Nicholas Hamilton Nov 29 '20 at 01:22
  • @NicholasHamilton glad to help, mate – Sergey Benner Nov 30 '20 at 09:48
4

I know it has been a while, but i have found this article and i was wondering what you guys think about it, it looks elegant. https://productbuilder.wordpress.com/2013/09/06/using-a-single-global-db-connection-in-node-js/

It basically say to use Node.js global.varName mechanism to share the connection globally.

BTW, i have tried it my self, and it worked seamlessly.

TBE
  • 1,002
  • 1
  • 11
  • 32
2

This sample project on GitHub is a brilliantly simple way to accomplish your goal. It's elegant and effective: https://github.com/fbeshears/register_models. The main code is:

(function(){
  module.exports = function(){
    var mongoose = require('mongoose');
    var Schema = mongoose.Schema; 
    var files = ['kitten.js', 'comments.js'];
    var fn = 0;
            for(fn in files) {
            var path_fn = "./" + files[fn];
            var exported_model = require(path_fn);
            exported_model(mongoose, Schema);
        }

    };
})();

I make a dir called 'models' under my main app dir and put this in the folder and require it, then call register_models();

regretoverflow
  • 2,093
  • 1
  • 23
  • 45
-1

I hope this is resolved by now, but just in case somebody finds it helpful. In short changing to

var conn = mongoose.createConnection(..)

Requires that all Schemas are registered for this connections. Meaning, instead of User = mongoose.model(...) you need User = db.model(...)

More details with links here: diff between .createConnection vs .connect

Community
  • 1
  • 1