Hey guys so I'm pretty new to creating modules, I'm having a bit of trouble accessing my mongodb connection pool from my main application.
Here's the module:
// mongo-pool.js
// -------------
var assert = require('assert');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var url = 'connection_url';
var mongoPool = {
start: function() {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Successfully connected to mongo");
// Make the db object accessible here?
});
}
}
module.exports = mongoPool;
When I require mongo-pool.js and call mongoPool.start() It says it successfully connected to mongo, although the db object is not accessible to make queries. Here is the main js file:
var mongoPool = require('./mongo-pool.js');
var pool = mongoPool.start();
var collection = pool.db.collection('accounts');
collection.update(
{ _id: 'DiyNaiis' },
{ $push: { children: 'JULIAN' } }
)
The variable pool is undefined. I can't seem to figure out why, I've tried return db in the module, didn't seem to work.
Any help is appreciated, thank you!
A buddy of mine helped me figure out what the problem was, here's the solution incase anyone runs into it.
I updated my mongo-pool.js module and assigned the db property to itself:
var assert = require('assert');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var url = 'my_database_url';
var mongoPool = {
start: function() {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
var self = this;
self.db = db;
// THESE ASSIGNMENTS
console.log("Successfully connected to mongo");
// Make the db object accessible here?
});
}
}
module.exports = mongoPool;
Then in my main.js file:
var mongoPool = require('./mongo-pool.js');
// Include My mongo global module
new mongoPool.start();
// Initialize the new MongoDB object globally
setTimeout(function() {
console.log(db);
}, 3000);
// Set a 3 second timeout before testing the db object...
// It will return undefined if it's called before the mongo connection is made
Now the db object is globally available from a module.
Related
I would like to connect to mongodb first, then run everything else in my application.
To do it I have to write something like:
MongoClient.connect("mongodb://localhost/test", function(err, connection) {
if (err) { console.error(err); }
db = connection;
var app = express();
// Include API V1
require("./apiv1.js")(app, db);
app.listen(3000, function(err) {
if (err) { console.error(err); } else { console.log("Started on *:3000"); }
});
});
This makes my app to be completely indented inside the .connect function... Which looks ugly and takes space while I work on my project.
I think the best solution would be have the MongoDB connection synchronous (even because witout the DB connection my app cannot work so why should I do something while it's connecting?) and then run the rest of my code.
How can I do?
You can't connect to MongoDB synchronously, but you may get rid of this ugly callback from your code.
The best way to do it is to adopt some wrapper around node-mongodb-native driver.
Take a look at the following modules.
mongojs
var mongojs = require('mongojs');
var db = mongojs('localhost/test');
var mycollection = db.collection('mycollection');
mongoskin
var mongo = require('mongoskin');
var db = mongo.db("mongodb://localhost:27017/test", {native_parser:true});
monk
var monk = require('monk');
var db = monk('localhost/test');
var users = db.get('users')
Of course, internally all of them are establishing MongoDB connection asynchronously.
Using the async library, you can aleve some of these issues.
For example in my server startup I do the following :
async.series([
function(callback){
// Initialize the mongodb connection and callback on completion in init.
db.init(function(){
callback();
});
},
function(callback){
// Listen on requests etc.
webServer.init(function(){
callback();
});
},
function(callback){
// Set up anything else that I need
callback();
}
]);
If you are using Node 6 and up versions, you can do something like this:
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017/mydb';
let db = null;
getdb();
//your code
async function getdb() {
db = await MongoClient.connect(url);
}
Bring the mongodb library.
Declare the url constant .
Declare the variable db as null.
Call the getdb function.
Create the getdb function which has firt the async word
Assign to the db variable the result of the connection with the key word await.
You can do it with thunky, thunky executes an async function once and caches it, the subsequent calls are returned from the cache.
const MongoClient = require('mongodb').MongoClient;
const thunky = require('thunky');
var connect = thunky(function(cb){
let url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, client){
console.log('connecting')
cb(err, client);
})
})
connect( (err, client) => {
console.log('connection 1')
})
connect( (err, client) => {
console.log('connection 2')
})
connect( (err, client) => {
console.log('connection 3')
console.log('closing')
client.close();
})
*Note: I am using latest 3.x mongodb driver
I am working on a nodejs / mongodb app using 'mongodb' module. The app is launched with
node main.js
In main.js, I connect to the db and keep the connection in the 'db' global variable. 'db' is then used in inner methods of 'server'. I want to avoid having 'db' as a global variable but did not found the correct way to do.
My current main.js:
var server = require('./lib/server');
var MongoClient = require('mongodb').MongoClient;
var Server = require('mongodb').Server;
var mongoClient = new MongoClient(new Server(HOST, PORT));
db = null;
// Database connection
mongoClient.open(function(err, mongoClient) {
if(!err){
// Database selection
db = mongoClient.db(DB);
// Launch web server
server.start(); // usage of 'db' in this part
} else {
console.log(err.message);
process.exit(1);
}
});
Any idea of a cleaner way ?
UPDATE
I finally created a module in connection.js:
var config = require('../config/config');
var url = 'mongodb://' + config.db.host + ':' + config.db.port + '/' + config.db.name;
var MongoClient = require('mongodb').MongoClient;
var db = null;
module.exports = function(cb){
if(db){
cb(db);
return;
}
MongoClient.connect(url, function(err, conn) {
if(err){
console.log(err.message);
throw new Error(err);
} else {
db = conn;
cb(db);
}
});
}
Each time I need to get the connection I call:
var connection = require('./connection');
connection(function(db){
// doing some stuff with the db
});
This is working very well.
Any potential failure with this approach ?
I typically include a project utilities file that contains a number of these things, just to make it easy. It functions as a pseudo global, but without many of the usual problems globals entail.
For example,
projectUtils.js
module.exports = {
initialize: function(next){
// initialization actions, there can be many of these
this.initializeDB(next);
},
initializeDb: function(next){
mongoClient.open(function(err, mongoClient) {
if(err) return next(err);
module.exports.db = mongoClient.db(DB);
next();
});
}
}
app.js
var projectUtils = require('projectUtils');
// (snip)
projectUtils.initialize(function(err) {
if(err) throw err; // bad DB initialization
// After this point and inside any of your routes,
// projectUtils.db is available for use.
app.listen(port);
}
By using an asynchronous initialize() function, you can be sure that all database connections, file I/O, etc., are done before starting up the server.
You can create a wrapper something like a provider and put it in provider.js, for instance.
Provider = function (db_name, host, port, username, password) {
var that = this;
var conn = generate_url(db_name, host, port, username, password); // you need to implement your version of generate_url()
MongoClient.connect(conn, function (err, db) {
if (err) {
throw err;
}
that.db = db;
});
};
//add the data access functions
Provider.prototype.getCollection = function (collectionName, callback) {
this.db.collection(collectionName, collectionOptions, callback);
};
exports.Provider = Provider;
This is how you use the provider:
var db = new Provider(db_name, host, port, username, password);
db.getCollection('collection name', callback);
I have an express/nodeJs app which will use mongo-db native client for persistance in Mongo-db. Now my problem is that most of the example I have seen have one collection and therefore do the connection in that js file, like this tutorial(which is mentioned in mongo-db native client docs). There the connection code is like this:
var Db = require('mongodb').Db;
var Connection = require('mongodb').Connection;
var Server = require('mongodb').Server;
var BSON = require('mongodb').BSON;
var ObjectID = require('mongodb').ObjectID;
ArticleProvider = function(host, port) {
this.db= new Db('node-mongo-blog', new Server(host, port, {auto_reconnect: true}, {}));
this.db.open(function(){});
};
ArticleProvider.prototype.getCollection= function(callback) {
this.db.collection('articles', function(error, article_collection) {
if( error ) callback(error);
else callback(null, article_collection);
});
};
ArticleProvider.prototype.findAll = function(callback) {
this.getCollection(function(error, article_collection) {
if( error ) callback(error)
else {
article_collection.find().toArray(function(error, results) {
if( error ) callback(error)
else callback(null, results)
});
}
});
};
There are other methods also which I kept out to keep it small(check in the above url for full tutorial).
My problem is that I have few more collections and therefore I am worried as to how to make a single connection to the database and use it for all the collections. I would also like if you can specify how to make connections to replica-sets also for reads and the main database for writes.
Or should I make calls to connections in each of my collection.js files like the above mentioned tutorial has done in one.
Please help me.
Try using the singleton pattern:
In your main express app.js connect to the database and create the database instance:
var Database = require('database.js');
...
mongodb.connect(config.dbAddress, function (err, db) {
if(err) {
return console.log('Error connection to DB');
}
Database.setDB(db);
app.listen(config.appPort);
});
Then in any other file you need to use the database require database.js again:
var Database = require('database.js');
...
ArticleProvider = function() {
this.db = Database.getDB();
};
...
Finally the database.js file follows the singleton pattern:
/**
Database Singleton Object
database.js is used throughout the app to access the db object. Using mongodb
native drivers the db object contains a pool of connections that are used to
make requests to the db. To use this singleton object simply require it and
either call getDB() or setDB(). The idea is to use setDB in app.js just
after we connect to the db and receive the db object, then in any other file we
need the db require and call getDB
**/
var mongodb = require('mongodb');
var singleton = (function() {
var instance; //Singleton Instance
function init() {
var _db; //Instance db object (private)
//Other private variables and function can be declared here
return {
//Gets the instance's db object
getDB: function() {
return _db;
},
//Sets the instance's db object
setDB: function(db) {
_db = db;
}
//Other public variables and methods can be declared here
};
}
return {
//getInstance returns the singleton instance or creates a new one if
//not present
getInstance: function() {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
module.exports = singleton.getInstance();
how do i share the db object returned from when i call db.open or db.connect across the entire app?
i have a dbconnect.js module as follows :
var mongodb = require('mongodb');
var global_db = '';
// Define options. Note poolSize.
var serverOptions = {
'auto_reconnect': true,
'poolSize': 5
};
// Now create the server, passing our options.
var serv = new mongodb.Server('localhost', 27017, serverOptions);
// At this point, there is no connection made to the server.
// Create a handle to the Mongo database called 'myDB'.
var dbManager = new mongodb.Db('myDB', serv);
// NOW we initialize ALL 5 connections:
dbManager.open(function (error, db) {
// Do something with the connection.
global_db = db;
// Make sure to call db.close() when ALL connections need
// to be shut down.
db.close();
});
function getConnection()
{
return global_db;
}
exports.getConnection = getConnection;
and i am using this dbconnect.js in my app.js as:
var http = require('http');
var db = require('./dbconnect').getConnection();
var collection = db.collection('testcollection');
console.log(db);
console.log(collection);
var server = http.createServer();
server.on('request',route);
server.listen(8000,'127.0.0.1');
console.log('Server running at http://127.0.0.1:8000');
function route(request,response)
{
var url = request.url;
var doc = {};
doc[url] = 'ok';
collection.insert(doc,{w:1},function(err,result)
{
if(err) console.log(err);
else console.log(result);
});
}
in the console, the db and collection variable show empty values, i also tried removing the db.close() call in dbconnect.js but to no use, however the insertion works when i place it inside dbconnect.js file in the dbManager.open function, how do i do this?or any similar alternatives?
You can't do that, because dbManager.open( is async method, but you trying to get data from module synchronously.
Try this:
In dbconnect.js
var on_db_ready = null;
module.exports = {
db_ready:function(db_ready_callback){
on_db_ready = db_ready_callback;
//here we call callback if already have db
if (global_db) on_db_ready(global_db);
},
getConnection:getConnection
};
dbManager.open(function (error, db) {
if (on_db_ready) on_db_ready(db);
global_db= db;
})
in app.js:
var db = require('./dbconnect').db_ready(function(db){
//Here i have my database
//or can use getConnection method
});
this is not very beautiful way, but, I hope, explain your mistake
How to connect to MongoDB with Node.js? And then pass the result to a client side JavaScript and display in HTML.
var http = require('http');
var URL = require('url');
var Db = require('mongodb').Db;
var Server = require('mongodb').Server;
var client = new Db('people', new Server("127.0.0.1", 27017, {}), { safe: false });
client.open(function (err, client) {
client.collection('people', listAllData);
});
var listAllData = function (err, collection) {
collection.find().toArray(function (err, results) {
console.log(results);
});
}
You should use Mongoose - elegant mongodb object modeling for node.js. http://mongoosejs.com
The quickstart guide is really cool, you should read it.
According to the documentation, here is a small example of how to use Mongoose:
var mongoose = require('mongoose');
var db = mongoose.createConnection('localhost', 'test');
var schema = mongoose.Schema({ name: 'string' });
var Cat = db.model('Cat', schema);
var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) // ...
console.log('meow');
});
I prefer MongoJS to Mongoose because it uses the same syntax used by the MongoDB Client syntax
https://github.com/gett/mongojs
// simple usage for a local db
var db = mongojs('mydb', ['mycollection']);
// the db is on a remote server (the port default to mongo)
var db = mongojs('example.com/mydb', ['mycollection']);
// we can also provide some credentials
var db = mongojs('username:password#example.com/mydb', ['mycollection']);
// connect now, and worry about collections later
var db = mongojs('mydb');
var mycollection = db.collection('mycollection');
Then you can use the same syntax as the Mongo Client
db.mycollection.find({}, function(err, docs) { ... });
db.mycollection.find({}).limit(2).skip(1, function(err, docs) { ... });