What I use is more or less this here:
- src/
- main.js
- modules/
- [controllers]
- [models]
- database.js
- [script variados: util.js, http-server.js, socket-server.js, etc]
- views/
- [templates: mustache|handlebars|whatever]
- routes/
- user.js (/user routes)
- admin.js (/admin routes)
- etc
- test/
- [units]
- [acceptances]
- etc
- util/
- [script empacotador do app]
- [scripts variados]
- package.json
- [yarn.lock|package-lock.json]
In database.js we will have the following:
'use strict';
const mongoClient = require('mongodb').MongoClient;
module.exports.isReady = new Promise(async (resolve, reject) => {
try {
//Connect MongoDB
let database = await mongoClient.connect(
'mongodb://localhost:27017', {useNewUrlParser: true}
);
console.log('Connected successfully');
//Select and return database connection
let db = database.db('dataPOA');
module.exports.conn = db;
resolve();
}
catch (err) {
reject(err);
}
});
The idea is you open a permanent connection at the beginning of the application. This connection will never be closed, you will reuse it throughout your app.
As the connection establishment is asynchronous we need a way to identify that the connection is ready for use and that we can start our application, hence the use of the Promise
isReady
(in module.exports.isReady
). Promise will only be resolved when the connection has been established.
Keeping in mind that the starting point of the application is the file main.js
, in it we’ll have something like this:
'use strict';
const DB = require('./modules/database');
DB.isReady.then(async () => {
console.info('Datbase is ready');
// let server = HttpServer();
// socket server
// um arquivo qualquer que faz algo com a db
require('./modules/dosomething');
// mais requires
// etc
}).catch((err) => {
console.error('damn', err);
process.exit(1);
});
modules/dosomething
is any file, in it we have an example of how you will use the pre-set connection:
'use strict';
// dosomething.js
const DB = require('./database');
const collection = DB.conn.collection('maybeMongodbIsNotTheBestChoice');
// obs poderíamos usar async/await aqui sem problemas
// caso isso estivesse encapsulado em uma funćão async
collection.insertMany([
{name: 'afasdfasdfa'},
{name: 'erqwqwerwqerwqer'}
]).then(() => {
return collection.find({}, {limit: 5}).toArray();
}).then((res) => {
console.info(res);
});
And that’s basically it, whenever you want to use the database you will require modules/database.js and use [DB].conn
. The crucial difference from this model to yours is that here DB.conn.[algum método]
(DB.conn.collection('minhacollection')
) nay establishes a new connection with the bank, only reuses the one made in main.js
at the first require of modules/database.js
. In his example all time we called mongodbConnection.collection('minhacollection')
we are establishing a new connection with the bank and the mongodb documentation itself already recommends avoiding that Pattern.
I also provided an example on https://github.com/BrunoRB/so-pt-304009-como-organizar-um-projeto-em-node, just clone the project, run npm|Yarn install inside the main folder and run node src/main.js
.
Finally I hope that it is clear that although the example uses mongodb
this template is not restricted to it. In dbs like mysql or sqlite you can (and I recommend) use a similar pattern, with the appropriate changes of course. For example: using mysql
you not only want to expect that the connection has been established, but also that all your tables, views, triggers, etc., have been created before you start using the connection. For that we would need to adapt the isReady
so that he just calls the resolve
after all their CREATE TABLE
(and the like) have completed.
I come from PHP and it’s kind of strange to think about creating a connection and always keep it open. And the use of
try catch
, recommends or whatever?– Costamilam
How do you use this connection on your controllers or routers? Import the database module again?
– Costamilam
I understand your point, it is really exotic to come from a language where you instantiate a connection to each new request and come across Ode and have the connection always open, but this is normal. About
try...catch
, the app has no use without the DB, so you can put the Try...catch, log the error and give aprocess.exit(1)
no catch, or just let it explode and fail. at all times import the filedatabase.js
, where she settled, in case the:const connection = require('./modules/database.js');
– BrunoRB
Ok. I still don’t understand very well, in case I have the files inside the folder
service
, where I have the functions that access the bank, I need that variable there, how does it get there? could give an example of a bank access function?– Costamilam
The files of
service/
wouldconst connection = require('./../modules/database.js');
, having access to the connection object that was already created when you started the app running something likenode main.js
. I’m a little out of time right now, but if you still need it tomorrow night, I’ll create a complete example for you to see the idea in operation.– BrunoRB
That’s more or less what I do, but it seems that this way he’s looking for a new connection in each
require
– Costamilam
In what you do a function is exported, this function instantiates a new Connection every time it is invoked. So if you have
const c = require('mongodbConnection.js').connection(collection)
, This generates a new connection because it runs all that function block that you exported. In what I suggested not, the connection would be created in the database.js already when it is first required, requires subsquentes do not create a new connection by in Node require() is curly. The whole difference is in you exporting a function that generates a Connection, where I suggest exporting to Connection directly.– BrunoRB
If you have please add that example please
– Costamilam
@Guilhermecostamilam see if it’s clearer now, I’ve added a (almost) complete example using mongodb.
– BrunoRB