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.
Related
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();
}
}
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.
I built a nodejs server to act as an adapter server, which upon receiving a post request containing some data, extracts the data from the request body and then forwards it to a few other external servers. Finally, my server will send a response consisting of the responses from each of the external server (success/fail).
If there's only 1 endpoint to forward to, it seems fairly straightforward. However, when I have to forward to more than one servers, I have to rely on things like Promise.All(), which has a fail-fast behaviour. That means if one promise is rejected (an external server is down), all other promises will also be rejected immediately and the rest the servers will not receive my data.
May be this ain't be the exact solution. But, what I am posting could be the work around of your problem.
Few days back I had the same problem, as I wanted to implement API versioning. Here is the solution I implemented, please have a look.
Architecture Diagram
Let me explain this diagram
Here in the diagram is the initial configuration for the server as we do. all the api request come here will pass to the "index.js" file inside the release directory.
index.js (in release directory)
const express = require('express');
const fid = require('./core/file.helper');
const router = express.Router();
fid.getFiles(__dirname,'./release').then(releases => {
releases.forEach(release => {
// release = release.replace(/.js/g,'');
router.use(`/${release}`,require(`./release/${release}/index`))
})
})
module.exports = router
code snippet for helper.js
//requiring path and fs modules
const path = require('path');
const fs = require('fs');
module.exports = {
getFiles: (presentDirectory, directoryName) => {
return new Promise((resolve, reject) => {
//joining path of directory
const directoryPath = path.join(presentDirectory, directoryName);
//passsing directoryPath and callback function
fs.readdir(directoryPath, function (err, files) {
// console.log(files);
//handling error
if (err) {
console.log('Unable to scan directory: ' + err);
reject(err)
}
//listing all files using forEach
// files.forEach(function (file) {
// // Do whatever you want to do with the file
// console.log(file);
// });
resolve(files)
});
})
}
}
Now, from this index file all the index.js inside each version folder is mapped
Here is the code bellow for "index.js" inside v1 or v2 ...
const express = require('express');
const mongoose = require('mongoose');
const fid = require('../../core/file.helper');
const dbconf = require('./config/datastore');
const router = express.Router();
// const connection_string = `mongodb+srv://${dbconf.atlas.username}:${dbconf.atlas.password}#${dbconf.atlas.host}/${dbconf.atlas.database}`;
const connection_string = `mongodb://${dbconf.default.username}:${dbconf.default.password}#${dbconf.default.host}:${dbconf.default.port}/${dbconf.default.database}`;
mongoose.connect(connection_string,{
useCreateIndex: true,
useNewUrlParser:true
}).then(status => {
console.log(`Database connected to mongodb://${dbconf.atlas.username}#${dbconf.atlas.host}/${dbconf.atlas.database}`);
fid.getFiles(__dirname,'./endpoints').then(files => {
files.forEach(file => {
file = file.replace(/.js/g,'');
router.use(`/${file}`,require(`./endpoints/${file}`))
});
})
}).catch(err => {
console.log(`Error connecting database ${err}`);
})
module.exports = router
In each of this index.js inside version folder is actually mapped to each endpoints inside endpoints folder.
code for one of the endpoints is given bellow
const express = require('express');
const router = express.Router();
const userCtrl = require('../controllers/users');
router.post('/signup', userCtrl.signup);
router.post('/login', userCtrl.login);
module.exports = router;
Here in this file actually we are connecting the endpoints to its controllers.
var config = {'targets':
[
'https://abc.api.xxx',
'https://xyz.abc',
'https://stackoverflow.net'
]};
relay(req, resp, config);
function relay(req, resp, config) {
doRelay(req, resp, config['targets'], relayOne);
}
function doRelay(req, resp, servers, relayOne) {
var finalresponses = [];
if (servers.length > 0) {
var loop = function(servers, index, relayOne, done) {
relayOne(req, servers[index], function(response) {
finalresponses.push[response];
if (++index < servers.length) {
setTimeout(function(){
loop(servers, index, relayOne, done);
}, 0);
} else {
done(resp, finalresponses);
}
});
};
loop(servers, 0, relayOne, done);
} else {
done(resp, finalresponses);
}
}
function relayOne(req, targetserver, relaydone) {
//call the targetserver and return the response data
/*return relaydone(response data);*/
}
function done(resp, finalresponses){
console.log('ended');
resp.writeHead(200, 'OK', {
'Content-Type' : 'text/plain'
});
resp.end(finalresponses);
return;
}
It sounds like you are trying to design a reverse proxy. If you are struggling to get custom code to work, there is a free npm library which is very robust.
I would recommend node-http-proxy
I have posted link below, which will lead you directly to the "modify response", since you mentioned modification of the API format in your question. Be sure to read the entire page though.
https://github.com/http-party/node-http-proxy#modify-a-response-from-a-proxied-server
Note: this library is also very good because it can support SSL, and proxies to both localhost (servers on the same machine) and servers on other machines (remote).
Promise.all() from MDN
It rejects with the reason of the first promise that rejects.
To overcome the problem, you'll need to catch() each request you've made.
e.g.
Promise.all([
request('<url 1>').catch(err => /* .. error handling */),
request('<url 2>').catch(err => /* .. error handling */),
request('<url 3>').catch(err => /* .. error handling */)
])
.then(([result1, result2, result3]) => {
if(result1.err) { }
if(result2.err) { }
if(result3.err) { }
})
I am creating an API with Node.js and Express. I'm using Postgres as DB.
I would like to create a "global object", called DBConn or something, that I can access from everywhere in the App. This object would have the functions for inserting, updating, validating, etc.
How would be the general architecture in Node and Express for this to work? Does it make sense in Node to instantiate it just once and keep the communication with the DB open, or should I instantiate it everytime I want to perform a DB action?
Here's everything that you are looking for, using pg-promise:
// Users repository:
var repUsers = function (obj) {
return {
add: function (name) {
return obj.none("insert into users(name) values($1)", name);
},
delete: function (id) {
return obj.none("delete from users where id=$1", id);
}
// etc...
};
};
var options = {
extend: function () {
// extending the protocol:
this.users = repUsers(this);
}
};
var pgp = require('pg-promise')(options);
var cn = "postgres://username:password#host:port/database";
var db = pgp(cn); // your global database instance;
db.users.add("John")
.then(function () {
// success;
})
.catch(function (error) {
// error;
});
This will also manage your database connection automatically, you will just keep using variable db throughout your application.
And setting up a repository is optional, you can always use in-line queries instead. See the library for details and more examples.
I don't know Postgres at all,but maybe you can try this:
Create a file named 'DBConn.js' in YourApp/common directory.
DBConn.js:
var DBConn = exports = modules.exports = {}
//code to connect to database
....
//insert update detele select
DBConn.insert = function(arguments) {
//some code
}
.....
DBConn.update = function(arguments) {
//some code
}
Then you can require it in any other controller like YouApp/controller/UserController.js
UserController.js:
var DBConn = require('../common/DBConn.js')
Example of module cache
index.js:
require('./DB.js');
require('./DB.js');
DB.js
var DB = exports = module.exports = {}
function connect() {
//connect to database code
console.log('Connect!');
}
connect();
//other code
Then node index.js,we can see that 'Connect!' only logged once.
Because when we first require('DB.js'),node.js put it to the module cache,and when we require DB.js again,we get DB.js from cache.
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() };