Mongo DB connection pooling or connection persistence - Which is better? [duplicate] - node.js

I'm using the node-mongodb-native driver with MongoDB to write a website.
I have some questions about how to manage connections:
Is it enough using only one MongoDB connection for all requests? Are there any performance issues? If not, can I setup a global connection to use in the whole application?
If not, is it good if I open a new connection when request arrives, and close it when handled the request? Is it expensive to open and close a connection?
Should I use a global connection pool? I hear the driver has a native connection pool. Is it a good choice?
If I use a connection pool, how many connections should be used?
Are there other things I should notice?

The primary committer to node-mongodb-native says:
You open do MongoClient.connect once when your app boots up and reuse
the db object. It's not a singleton connection pool each .connect
creates a new connection pool.
So, to answer your question directly, reuse the db object that results from MongoClient.connect(). This gives you pooling, and will provide a noticeable speed increase as compared with opening/closing connections on each db action.

Open a new connection when the Node.js application starts, and reuse the existing db connection object:
/server.js
import express from 'express';
import Promise from 'bluebird';
import logger from 'winston';
import { MongoClient } from 'mongodb';
import config from './config';
import usersRestApi from './api/users';
const app = express();
app.use('/api/users', usersRestApi);
app.get('/', (req, res) => {
res.send('Hello World');
});
// Create a MongoDB connection pool and start the application
// after the database connection is ready
MongoClient.connect(config.database.url, { promiseLibrary: Promise }, (err, db) => {
if (err) {
logger.warn(`Failed to connect to the database. ${err.stack}`);
}
app.locals.db = db;
app.listen(config.port, () => {
logger.info(`Node.js app is listening at http://localhost:${config.port}`);
});
});
/api/users.js
import { Router } from 'express';
import { ObjectID } from 'mongodb';
const router = new Router();
router.get('/:id', async (req, res, next) => {
try {
const db = req.app.locals.db;
const id = new ObjectID(req.params.id);
const user = await db.collection('user').findOne({ _id: id }, {
email: 1,
firstName: 1,
lastName: 1
});
if (user) {
user.id = req.params.id;
res.send(user);
} else {
res.sendStatus(404);
}
} catch (err) {
next(err);
}
});
export default router;
Source: How to Open Database Connections in a Node.js/Express App

Here is some code that will manage your MongoDB connections.
var MongoClient = require('mongodb').MongoClient;
var url = require("../config.json")["MongoDBURL"]
var option = {
db:{
numberOfRetries : 5
},
server: {
auto_reconnect: true,
poolSize : 40,
socketOptions: {
connectTimeoutMS: 500
}
},
replSet: {},
mongos: {}
};
function MongoPool(){}
var p_db;
function initPool(cb){
MongoClient.connect(url, option, function(err, db) {
if (err) throw err;
p_db = db;
if(cb && typeof(cb) == 'function')
cb(p_db);
});
return MongoPool;
}
MongoPool.initPool = initPool;
function getInstance(cb){
if(!p_db){
initPool(cb)
}
else{
if(cb && typeof(cb) == 'function')
cb(p_db);
}
}
MongoPool.getInstance = getInstance;
module.exports = MongoPool;
When you start the server, call initPool
require("mongo-pool").initPool();
Then in any other module you can do the following:
var MongoPool = require("mongo-pool");
MongoPool.getInstance(function (db){
// Query your MongoDB database.
});
This is based on MongoDB documentation. Take a look at it.

Manage mongo connection pools in a single self contained module. This approach provides two benefits. Firstly it keeps your code modular and easier to test. Secondly your not forced to mix your database connection up in your request object which is NOT the place for a database connection object. (Given the nature of JavaScript I would consider it highly dangerous to mix in anything to an object constructed by library code). So with that you only need to Consider a module that exports two methods. connect = () => Promise and get = () => dbConnectionObject.
With such a module you can firstly connect to the database
// runs in boot.js or what ever file your application starts with
const db = require('./myAwesomeDbModule');
db.connect()
.then(() => console.log('database connected'))
.then(() => bootMyApplication())
.catch((e) => {
console.error(e);
// Always hard exit on a database connection error
process.exit(1);
});
When in flight your app can simply call get() when it needs a DB connection.
const db = require('./myAwesomeDbModule');
db.get().find(...)... // I have excluded code here to keep the example simple
If you set up your db module in the same way as the following not only will you have a way to ensure that your application will not boot unless you have a database connection you also have a global way of accessing your database connection pool that will error if you have not got a connection.
// myAwesomeDbModule.js
let connection = null;
module.exports.connect = () => new Promise((resolve, reject) => {
MongoClient.connect(url, option, function(err, db) {
if (err) { reject(err); return; };
resolve(db);
connection = db;
});
});
module.exports.get = () => {
if(!connection) {
throw new Error('Call connect first!');
}
return connection;
}

If you have Express.js, you can use express-mongo-db for caching and sharing the MongoDB connection between requests without a pool (since the accepted answer says it is the right way to share the connection).
If not - you can look at its source code and use it in another framework.

You should create a connection as service then reuse it when need.
// db.service.js
import { MongoClient } from "mongodb";
import database from "../config/database";
const dbService = {
db: undefined,
connect: callback => {
MongoClient.connect(database.uri, function(err, data) {
if (err) {
MongoClient.close();
callback(err);
}
dbService.db = data;
console.log("Connected to database");
callback(null);
});
}
};
export default dbService;
my App.js sample
// App Start
dbService.connect(err => {
if (err) {
console.log("Error: ", err);
process.exit(1);
}
server.listen(config.port, () => {
console.log(`Api runnning at ${config.port}`);
});
});
and use it wherever you want with
import dbService from "db.service.js"
const db = dbService.db

I have been using generic-pool with redis connections in my app - I highly recommend it. Its generic and I definitely know it works with mysql so I don't think you'll have any problems with it and mongo
https://github.com/coopernurse/node-pool

I have implemented below code in my project to implement connection pooling in my code so it will create a minimum connection in my project and reuse available connection
/* Mongo.js*/
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/yourdatabasename";
var assert = require('assert');
var connection=[];
// Create the database connection
establishConnection = function(callback){
MongoClient.connect(url, { poolSize: 10 },function(err, db) {
assert.equal(null, err);
connection = db
if(typeof callback === 'function' && callback())
callback(connection)
}
)
}
function getconnection(){
return connection
}
module.exports = {
establishConnection:establishConnection,
getconnection:getconnection
}
/*app.js*/
// establish one connection with all other routes will use.
var db = require('./routes/mongo')
db.establishConnection();
//you can also call with callback if you wanna create any collection at starting
/*
db.establishConnection(function(conn){
conn.createCollection("collectionName", function(err, res) {
if (err) throw err;
console.log("Collection created!");
});
};
*/
// anyother route.js
var db = require('./mongo')
router.get('/', function(req, res, next) {
var connection = db.getconnection()
res.send("Hello");
});

If using express there is another more straightforward method, which is to utilise Express's built in feature to share data between routes and modules within your app. There is an object called app.locals. We can attach properties to it and access it from inside our routes. To use it, instantiate your mongo connection in your app.js file.
var app = express();
MongoClient.connect('mongodb://localhost:27017/')
.then(client =>{
const db = client.db('your-db');
const collection = db.collection('your-collection');
app.locals.collection = collection;
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
This database connection, or indeed any other data you wish to share around the modules of you app can now be accessed within your routes with req.app.locals as below without the need for creating and requiring additional modules.
app.get('/', (req, res) => {
const collection = req.app.locals.collection;
collection.find({}).toArray()
.then(response => res.status(200).json(response))
.catch(error => console.error(error));
});
This method ensures that you have a database connection open for the duration of your app unless you choose to close it at any time. It's easily accessible with req.app.locals.your-collection and doesn't require creation of any additional modules.

Best approach to implement connection pooling is you should create one global array variable which hold db name with connection object returned by MongoClient and then reuse that connection whenever you need to contact Database.
In your Server.js define var global.dbconnections = [];
Create a Service naming connectionService.js. It will have 2 methods getConnection and createConnection.
So when user will call getConnection(), it will find detail in global connection variable and return connection details if already exists else it will call createConnection() and return connection Details.
Call this service using <db_name> and it will return connection object if it already have else it will create new connection and return it to you.
Hope it helps :)
Here is the connectionService.js code:
var mongo = require('mongoskin');
var mongodb = require('mongodb');
var Q = require('q');
var service = {};
service.getConnection = getConnection ;
module.exports = service;
function getConnection(appDB){
var deferred = Q.defer();
var connectionDetails=global.dbconnections.find(item=>item.appDB==appDB)
if(connectionDetails){deferred.resolve(connectionDetails.connection);
}else{createConnection(appDB).then(function(connectionDetails){
deferred.resolve(connectionDetails);})
}
return deferred.promise;
}
function createConnection(appDB){
var deferred = Q.defer();
mongodb.MongoClient.connect(connectionServer + appDB, (err,database)=>
{
if(err) deferred.reject(err.name + ': ' + err.message);
global.dbconnections.push({appDB: appDB, connection: database});
deferred.resolve(database);
})
return deferred.promise;
}

In case anyone wants something that works in 2021 with Typescript, here's what I'm using:
import { MongoClient, Collection } from "mongodb";
const FILE_DB_HOST = process.env.FILE_DB_HOST as string;
const FILE_DB_DATABASE = process.env.FILE_DB_DATABASE as string;
const FILES_COLLECTION = process.env.FILES_COLLECTION as string;
if (!FILE_DB_HOST || !FILE_DB_DATABASE || !FILES_COLLECTION) {
throw "Missing FILE_DB_HOST, FILE_DB_DATABASE, or FILES_COLLECTION environment variables.";
}
const client = new MongoClient(FILE_DB_HOST, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
class Mongoose {
static FilesCollection: Collection;
static async init() {
const connection = await client.connect();
const FileDB = connection.db(FILE_DB_DATABASE);
Mongoose.FilesCollection = FileDB.collection(FILES_COLLECTION);
}
}
Mongoose.init();
export default Mongoose;
I believe if a request occurs too soon (before Mongo.init() has time to finish), an error will be thrown, since Mongoose.FilesCollection will be undefined.
import { Request, Response, NextFunction } from "express";
import Mongoose from "../../mongoose";
export default async function GetFile(req: Request, res: Response, next: NextFunction) {
const files = Mongoose.FilesCollection;
const file = await files.findOne({ fileName: "hello" });
res.send(file);
}
For example, if you call files.findOne({ ... }) and Mongoose.FilesCollection is undefined, then you will get an error.

npm i express mongoose
mongodb.js
const express = require('express');
const mongoose =require('mongoose')
const app = express();
mongoose.set('strictQuery', true);
mongoose.connect('mongodb://localhost:27017/db_name', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('MongoDB Connected...'))
.catch((err) => console.log(err))
app.listen(3000,()=>{ console.log("Started on port 3000 !!!") })
node mongodb.js

Using below method you can easily manage as many as possible connection
var mongoose = require('mongoose');
//Set up default mongoose connection
const bankDB = ()=>{
return mongoose.createConnection('mongodb+srv://<username>:<passwprd>#mydemo.jk4nr.mongodb.net/<database>?retryWrites=true&w=majority',options);
}
bankDB().then(()=>console.log('Connected to mongoDB-Atlas bankApp...'))
.catch((err)=>console.error('Could not connected to mongoDB',err));
//Set up second mongoose connection
const myDB = ()=>{
return mongoose.createConnection('mongodb+srv://<username>:<password>#mydemo.jk4nr.mongodb.net/<database>?retryWrites=true&w=majority',options);
}
myDB().then(()=>console.log('Connected to mongoDB-Atlas connection 2...'))
.catch((err)=>console.error('Could not connected to mongoDB',err));
module.exports = { bankDB(), myDB() };

Related

Mongodb native connections from nodejs return undefined databases list

I'm just starting to use Mongodb without mongoose (to get away from the schemas), and wanted to create a simple module with various exported functions to use in the rest of my app. I've pasted the code below.
The problem I'm having is that the databasesList.databases comes back as undefined, and I'm not sure why. There should be 2 databases on my cluster, and one collection in each database.
As a tangential question, I thought maybe I would check the collections instead (now commented out), but though I found this page (https://docs.mongodb.com/manual/reference/method/db.getCollectionNames/) the function getCollectionNames seems not to exist. Now I'm wondering if I'm using the wrong documentation and that is why my databases are coming back undefined.
const client = new MongoClient(uri)
const connection = client.connect( function (err, database) {
if (err) throw err;
else if (!database) console.log('Unknown error connecting to database');
else {
console.log('Connected to MongoDB database server');
}
});
module.exports = {
getDatabaseList: function() {
console.log('start ' + client);
databasesList = client.db().admin().listDatabases();
//collectionList = client.db().getCollectionNames();
//console.log("Collections: " + collectionList);
console.log("Databases: " + databasesList.databases);
//databasesList.databases.forEach(db => console.log(` - ${db.name}`));
}
}```
your code is correct Just need to change few things.
module.exports = {
getDatabaseList: async function() {
console.log('start ' + client);
databasesList = await client.db().admin().listDatabases();
//collectionList = await client.db().getCollectionNames();
//console.log("Collections: " + collectionList);
console.log("Databases: " + databasesList.databases);
databasesList.databases.forEach(db => console.log(` - ${db.name}`));
}
}
You have to declare async function and use await also.
The async and await keywords enable asynchronous, promise-based behaviour to be written in a cleaner style, avoiding the need to explicitly configure promise chains.
You can use this modular approach to build your database access code:
index.js: Run your database application code, like list database names, collection names and read from a collection.
const connect = require('./database');
const dbFunctions = require('./dbFunctions');
const start = async function() {
const connection = await connect();
console.log('Connected...');
const dbNames = await dbFunctions.getDbNames(connection);
console.log(await dbNames.databases.map(e => e.name));
const colls = await dbFunctions.getCollNames(connection, 'test');
console.log(await colls.map(e => e.name));
console.log(await dbFunctions.getDocs(connection, 'test', 'test'));
};
start();
database.js:: Create a connection object. This connection is used for all your database access code. In general, a single connection creates a connection pool and this can be used throughout a small application
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017/';
const opts = { useUnifiedTopology: true };
async function connect() {
console.log('Connecting to db server...');
return await MongoClient.connect(url, opts );
}
module.exports = connect;
dbFunctions.js:: Various functions to access database details, collection details and query a specific collection.
module.exports = {
// return list of database names
getDbNames: async function(conn) {
return await conn.db().admin().listDatabases( { nameOnly: true } );
},
// return collections list as an array for a given database
getCollNames: async function(conn, db) {
return await conn.db(db).listCollections().toArray();
},
// return documents as an array for a given database and collection
getDocs: async function(conn, db, coll) {
return await conn.db(db).collection(coll).find().toArray();
}
}

Node.js mongoose unable to 'save()' a document on MongoDB database

My problem is quite peculiar, as I believe to have done everything "by the book".
I'm able to successfully connect to a MongoDB cluster I've created through MongoDB Atlas. When I make a 'POST' request to save a choice that was picked from an array of choices, I successfully create a document through the Model specified below. I then try to save that document to MongoDB by calling the 'save()' method, but it hangs and nothing comes out of it (even if I use a 'catch' to see if any errors occurred).
I'm completely lost as to what is wrong, and what I need to do to solve this. I was hoping you could give me some pointers.
MongoDB connection, schema, and model:
const mongoose = require('mongoose');
const URL = process.env.MONGODB_URL;
mongoose.connect(URL, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log('Successfully connected to our MongoDB database.');
}).catch((error) => {
console.log('Could not connect to our MongoDB database.', error.message);
});
const choicesMadeSchema = new mongoose.Schema({
allChoices: Array,
pickedChoice: String
});
const ChoiceMade = mongoose.model('ChoiceMade', choicesMadeSchema);
module.exports = ChoiceMade; // Exports our 'ChoiceMade' constructor, to be used by other modules.
index.js:
/* 1 - Setting things up */
require('dotenv').config();
const express = require('express');
const server = express();
const PORT = process.env.PORT;
const parserOfRequestBody = require('body-parser');
server.use(parserOfRequestBody.json());
/* 2 - Retrieving all the data we need from our 'MongoDB' database */
// Imports the 'mongoose' library, which will allow us to easily interact with our 'MongoDB' database.
const mongoose = require('mongoose');
// Imports our 'ChoiceMade' constructor.
const ChoiceMade = require('./database/database.js');
// Will hold the five latest choices that have been made (and thus saved on our 'MongoDB' database).
let fiveLatestChoicesMade;
// Retrieves the five latest choices that have been made (and thus saved on our 'MongoDB' database).
ChoiceMade.find({}).then((allChoicesEverMade) => {
const allChoicesEverMadeArray = allChoicesEverMade.map((choiceMade) => {
return choiceMade.toJSON();
});
fiveLatestChoicesMade = allChoicesEverMadeArray.slice(allChoicesEverMadeArray.length - 5).reverse();
console.log("These are the five latest choices that have been made:", fiveLatestChoicesMade);
mongoose.connection.close();
});
/* 3 - How the server should handle requests */
// 'GET' (i.e., 'retrieve') requests
server.get('/allChoicesMade', (request, response) => {
console.log("This is the data that will be sent as a response to the 'GET' request:", fiveLatestChoicesMade);
response.json(fiveLatestChoicesMade);
});
// 'POST' (i.e., 'send') requests
server.post('/allChoicesMade', (request, response) => {
const newChoiceMadeData = request.body;
if (Object.keys(newChoiceMadeData).length === 0) {
return response.status(400).json({ error: "No data was provided." });
}
const newChoiceMade = new ChoiceMade({
allChoices: newChoiceMadeData.allChoices,
pickedChoice: newChoiceMadeData.pickedChoice
});
console.log("This is the new 'choice made' entry that we are going to save on our 'MongoDB' database:", newChoiceMade); // All good until here
newChoiceMade.save().then((savedChoiceMade) => {
console.log('The choice that was made has been saved!');
response.json(savedChoiceMade);
mongoose.connection.close();
}).catch((error) => {
console.log('An error occurred:', error);
});
});
/* 4 - Telling the server to 'listen' for requests */
server.listen(PORT, () => {
console.log("Our 'Express' server is running, and listening for requests made to port '" + PORT + "'.");
});
SOLUTION TO THE PROBLEM
In my code's section 2, I was mistakenly closing the connection upon retrieving all the data I need to make my app work. I was doing this (...)
// Retrieves the five latest choices that have been made (and thus saved on our 'MongoDB' database).
ChoiceMade.find({}).then((allChoicesEverMade) => {
const allChoicesEverMadeArray = allChoicesEverMade.map((choiceMade) => {
return choiceMade.toJSON();
});
fiveLatestChoicesMade = allChoicesEverMadeArray.slice(allChoicesEverMadeArray.length - 5).reverse();
console.log("These are the five latest choices that have been made:", fiveLatestChoicesMade);
mongoose.connection.close(); // This should not be here!!!
});
(...) when I should be doing
// Retrieves the five latest choices that have been made (and thus saved on our 'MongoDB' database).
ChoiceMade.find({}).then((allChoicesEverMade) => {
const allChoicesEverMadeArray = allChoicesEverMade.map((choiceMade) => {
return choiceMade.toJSON();
});
fiveLatestChoicesMade = allChoicesEverMadeArray.slice(allChoicesEverMadeArray.length - 5).reverse();
console.log("These are the five latest choices that have been made:", fiveLatestChoicesMade);
// Now that I don't have mongoose.connection.close(), everything's OK!
});
Basically, and in my particular case, I was closing my connection to the MongoDB database after retrieving data from it, and then trying to add a new record to it when I didn't have a connection to it anymore.

Restful Api express postgres database

I´m developing a rest full api with node and exrpess, my database is postgresql, I need to use the postgres package pg-promise.
I know that I need to connect my app with the database in the app.js file, but my question is, How I should use this connection in my endpoints.
I have routes and I am using controllers.
For example
app.js
//in this file, suppously I have to to the connection
const db = pgp('postgres://john:pass123#localhost:5432/products');
app.use('/products', productsRoute);
products.js (route)
router.get('/', ProductsController.get_all_products);
products.js (controller)
exports.get_all_products = (req, res, next ) => {
// Here i want to use de database connection to do the query to find all
//products in the database
}
How do I get access to the connection to do something like
db.any('SELECT * FROM products WHERE active = $1', [true])
.then(function(data) {
// success;
})
.catch(function(error) {
// error;
});
From the controller.
Update
Ok, I´m using now node-prostgres, pg. I saw is better, Thanks for the advice people.
I want to create one time de db instance, and call it anywhere, in specific in the controllers
Could I use app.local to save my client?, connect, do a query and then close it. Do this anywhere
I haven't used pg-promise.
If it helps, you can use PostgreSQL client for Node.js. You can also use async/await with it.
Instead of a router, you can use Express middle-ware straightaway as follows.
//app.js:
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = 1234
const db = require('./dbconnector')
//...omitted for brevity`
// 'db' is exported from a file such as
// dbconnector.js.
app.get('/products', db.getProducts)
//In dbconnector.js:
const Pool = require('pg').Pool
const pool = new Pool({
user: 'postgres',
host: 'localhost',
database: 'mydb',
password: 'mypwd',
port: 5432,
})
const getProducts = (request, response) => {
pool.query('SELECT * FROM products ORDER BY id
ASC', (error, results) => {
if (error) {
throw error
}
response.status(200).json(results.rows)
})
}
// ...omitted for brevity
module.exports = {
getProducts
}
For modular design, please use a separate file (not app.js/index.js/server.js) for db connections as best practice and require that in your main app.js.
Here is help on pg module.
Here's an example how to use it:
// mydb.js
async function someDbQuery() {
let result;
try {
result = db.any('SELECT * FROM products WHERE active = $1', [true])
} catch (e) {
throw e
}
return result;
}
module.exports = someDbQuery;
// in your controller after importing
const { someDbQuery } = require('./mydb.js')
exports.get_all_products = async (req, res, next ) => {
// Here i want to use de database connection to do the query to find all
//products in the database
try {
const result = await someDbQuery();
// use result here
} catch (e) {
// handle error
console.error(e)
}
}
Side note:
From the docs pg-promise
Built on top of node-postgres
node-postgres now supports promise too.
You do not need to do anything, pg-promise manages connections automatically. It will be allocated for the query and released right after. See examples.

Best way to connect to MongoDB using Node.js [duplicate]

This question already has answers here:
How do I manage MongoDB connections in a Node.js web application?
(13 answers)
Closed 4 years ago.
I've read a few guides on how to use Mongo with Node, and they all seem to connect to databases differently. One particular way that worked well for me was:
MongoClient.connect("mongodb://localhost:27017/exampleDb", function(err, db) {
if(err) { return console.dir(err); }
db.createCollection('users', function(err, collection) {});
//Do all server/database operations in here
});
However, this seems inefficient/odd to me, I would have to reconnect to the database every time there is an app.get(), like for making a new user or retrieving information.
Another way that seems better suited to me is
var mongoose = require("mongoose")
var db = mongoose.connect("localhost:27107/users");
db.createCollection('users', function(err, collection) {});
I've seen several sites do something along these lines, but I personally can't get the above to work. I keep getting the error TypeError: db.createCollection is not a function server-side. So, my question is why the above code doesn't work, if the first code is a good alternative, and if there are any other ways to do this.
You can use a global variable to hold the connection (e.g. db), for example:
var db = null // global variable to hold the connection
MongoClient.connect('mongodb://localhost:27017/', function(err, client) {
if(err) { console.error(err) }
db = client.db('test') // once connected, assign the connection to the global variable
})
app.get('/', function(req, res) {
db.collection('test').find({}).toArray(function(err, docs) {
if(err) { console.error(err) }
res.send(JSON.stringify(docs))
})
})
Or, if you prefer, you can also use the Promise object that is returned by MongoClient if it is called without a callback argument:
var conn = MongoClient.connect('mongodb://localhost:27017/') // returns a Promise
app.get('/', function(req, res) {
conn.then(client=> client.db('test').collection('test').find({}).toArray(function(err, docs) {
if(err) { console.error(err) }
res.send(JSON.stringify(docs))
}))
})
Please note that I used the ES6 fat arrow function definition in the second example.
You are absolutely correct that you should not call MongoClient every time. Using a global variable or Promises allows the MongoDB node.js driver to create a connection pool, which achieves at least two good things:
Connections are reused in a pool, so there is no multiple expensive setup/teardown process for the lifetime of your application. You connect once, and let the driver take care of the rest for you.
You can control the amount of connection your application makes into the database, by limiting the size of the connection pool.
Edit 2018-08-24: The MongoClient.connect() method in node.js driver version 3.0 and newer returns a client object instead of a database object. The examples above were modified to keep it up to date with the latest node.js driver version.
I've written a tutorial on how to reuse mongodb connection in express. You can see here. Basically, it's a simple module, which you can use with expressjs like that:
var connection = require('./dbconnection');
// url and optional config.
app.use(connection(app, 'mongourl', {});
And here's the code for the connection:
module.exports = function(app, uri, opts) {
if (typeof uri !== 'string') {
throw new TypeError('Error: Unexpected mongodb connection url');
}
opts = opts || {};
var property = opts.property || 'db';
var connection;
return function expressMongoDb(req, res, next) {
if (!connection) {
connection = MongoClient.connect(uri, opts);
}
connection
.then(function (db) {
req[property] = db;
app.set('mongodb', db);
next();
})
.catch(function (err) {
connection = undefined;
next(err);
});
};
};
You could use it this way:
that's server.js file:
import path from 'path'
import express from 'express'
import bodyParser from 'body-parser'
import morgan from 'morgan'
import db from './server/database'
import routes from './server/routes'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import webpackConfig from './config/webpack'
const app = express()
const port = process.env.PORT || process.env.NODE_PORT
const compiler = webpack(webpackConfig)
db(λ => {
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: webpackConfig.output.publicPath }))
app.use(webpackHotMiddleware(compiler))
app.use(morgan('dev'))
app.use(bodyParser.json({ limit: '20mb' }))
app.use(bodyParser.urlencoded({ limit: '20mb', extended: false }))
app.use('/static', express.static('static'));
//app.use('/api', jwt)
app.use('/api', routes())
app.set('json spaces', 2)
app.get('*', function(request, response) {
response.sendFile(path.resolve(__dirname, 'index.html'))
})
app.listen(port, (error) => {
if (error) {
console.error(error)
throw error
} else {
console.info(`==> 🌎 Listening on port ${port}. Open up http://localhost:${port}/ in your browser.`)
}
})
})
server/database.js
import mongoose from 'mongoose'
export default callback => {
const { MONGO_URL, MONGO_PORT, MONGO_DB } = process.env
mongoose.connect(`mongodb://${MONGO_URL}:${MONGO_PORT}/${MONGO_DB}`, error => {
if (error) {
console.error('Please make sure your MongoDB configuration is correct and that service is running')
throw error
}
})
callback()
}
Then you'll have to define your mongoose models, for instance:
import mongoose, { Schema } from 'mongoose'
const ideaSchema = new Schema({
title: {
type: String,
required: true
},
slug: {
type: String,
required: true,
unique: true
},
description: {
type: String,
required: true
}
})
export default mongoose.model('Idea', ideaSchema)
And just use controllers this way:
import HttpStatus from 'http-status-codes'
import mongoose from 'mongoose'
import sanitize from 'sanitize-html'
import slug from 'slug'
import Idea from '../models/idea'
const findAllIdeas = (req, res) => {
Idea.find()
.select('user title slug createdAt updatedAt')
.populate({
path: 'user',
select: 'firstName lastName'
})
.then(data => res.status(HttpStatus.OK).json(data))
.catch(error => res.status(HttpStatus.BAD_REQUEST).json(error))
}
export default { findAllIdeas, findIdeaBySlug, createIdea, addComment }
You will not have to connect to mongoDB for each get request.
So your route will look like that. Quite straightforward:
import { Router } from 'express'
import controller from '../controllers/idea'
const router = Router()
router.route('/')
.get(controller.findAllIdeas)
.post(controller.createIdea)
router.route('/:slug')
.get(controller.findIdeaBySlug)
router.route('/comment')
.post(controller.addComment)
export default router
My go-to code is as follows:
mongoose.connect(YOUR_URL ,function(err) {
if (err) {
console.log(err);
}else{
console.log("Connected to DB");
}
});
Also try connecting to just localhost:27107, that may be your problem.

Connect synchronously to mongodb

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

Resources