How to organize a project in node

10

I would like some idea of how I could organize a project in node.js, currently the files look like this:

- router.js
- controller
    L controllerUser.js
    L controllerAuth.js
    L ...
- service
    L mongodbConnection.js
    L serviceUser.js
    L ...

In the service it's basically a CRUD (for now):

const mongodbConnection = require('./mongodbConnection.js');

//Find document of collection user by propriety name
module.exports.findByName = async function(object) {
    let connection = await mongodbConnection.connection(collection);

    let select = await connection.find(object);

    return select.toArray();
}

In the service the connection to the database, in this case, mongodb, is through a module:

const mongoClient = require('mongodb').MongoClient;

module.exports.connection = async function(collection) {
    try {
        //Connect MongoDB
        let database = await mongoClient.connect('mongodb://localhost:27017');
        console.log('Connected successfully');

        //Select and return database connection
        return database.db('dataPOA').collection(collection);
    } catch (error) {
        console.log(error);
        return error;
    }
}
  • Starting a new connection at the beginning of each function is correct? It seems like a lot of code repetition, can you improve?
  • How to close this connection? Or should I leave it open?
  • Would not it be wise to put this code that performs functions in the database within a try catch ?
asked by anonymous 03.06.2018 / 04:22

3 answers

8

What I usually use is something like this:

- 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 to 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 set-up 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 Promise isReady (in module.exports.isReady ). The promise will only be resolved once the connection has been established.

Keeping in mind that the start point of the application is the file main.js , in it we will 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-established 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 it's basically this, whenever you want to use the database you will require modules / database.js and use [DB].conn . The crucial difference of this model to yours is that here DB.conn.[algum método] ( DB.conn.collection('minhacollection') ) does not establishes a new connection to the database, only reuses what was done in main.js on the first require of% with%. In your example time we call modules/database.js we are establishing a new connection to the bank and mongodb's own documentation already recommends avoiding this pattern.

I also have an example on link , just clone the project, run npm | yarn install inside the main folder and run mongodbConnection.collection('minhacollection') .

Finally I hope it is clear that although the example uses node src/main.js 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 mongodb you not only want to wait for the connection to be established, but also that all your tables, views, triggers, etc., have been created before you start using the connection. For this we would need to adapt the mysql so that it only calls the isReady after all its resolve (and similar) have completed.

    
26.06.2018 / 20:30
1

I recently met an framework with MVC standard for NodeJS. It's called Adonis . It's extremely organized and inherits a bit of Laravel's style.

The only bad thing is that it does not support MongoDB since it works with SQL in a pattern known as active record . However, I do not see this as a problem.

11.06.2018 / 21:27
1

Guilherme, read this material. I built on it to structure my project, and it explains very well the various cases that can be adopted and the best of them:

link link

    
25.06.2018 / 16:06