Keeping open a MongoDB database connection

node.jsMongodb

node.js Problem Overview


In so many introductory examples of using MongoDB, you see code like this:

var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:port/adatabase", function(err, db)
{
    /* Some operation... CRUD, etc. */
    db.close();
});

If MongoDB is like any other database system, open and close operations are typically expensive time-wise.

So, my question is this: Is it OK to simply do the MongoClient.connect("... once, assign the returned db value to some module global, have various functions in the module do various database-related work (insert documents into collections, update documents, etc. etc.) when they're called by other parts of the application (and thereby re-use that db value), and then, when the application is done, only then do the close.

In other words, open and close are done once - not every time you need to go and do some database-related operation. And you keep re-using that db object that was returned during the initial open\connect, only to dispose of it at the end, with the close, when you're actually done with all your database-related work.

Obviously, since all the I/O is asynch, before the close you'd make sure that the last database operation completed before issuing the close. Seems like this should be OK, but i wanted to double-check just in case I'm missing something as I'm new to MongoDB. Thanks!

node.js Solutions


Solution 1 - node.js

Yes, that is fine and typical behavior. start your app, connect to db, do operations against the db for a long time, maybe re-connect if the connection ever dies unexpectedly, and then just never close the connection (just rely on the automatic close that happens when your process dies).

Solution 2 - node.js

mongodb version ^3.1.8

Initialize the connection as a promise:

const MongoClient = require('mongodb').MongoClient
const uri = 'mongodb://...'
const client = new MongoClient(uri)
const connection = client.connect() // initialized connection

And then call the connection whenever you wish you perform an action on the database:

    // if I want to insert into the database...
    const connect = connection
    connect.then(() => {
        const doc = { id: 3 }
        const db = client.db('database_name')
        const coll = db.collection('collection_name')
        coll.insertOne(doc, (err, result) => {
            if(err) throw err
        })
    })

Solution 3 - node.js

The current accepted answer is correct in that you may keep the same database connection open to perform operations, however, it is missing details on how you can retry to connect if it closes. Below are two ways to automatically reconnect. It's in TypeScript, but it can easily be translated into normal Node.js if you need to.

Method 1: MongoClient Options

The most simple way to allow MongoDB to reconnect is to define a reconnectTries in an options when passing it into MongoClient. Any time a CRUD operation times out, it will use the parameters passed into MongoClient to decide how to retry (reconnect). Setting the option to Number.MAX_VALUE essentially makes it so that it retries forever until it's able to complete the operation. You can check out the driver source code if you want to see what errors will be retried.

class MongoDB {
    private db: Db;

    constructor() {
        this.connectToMongoDB();
    }

    async connectToMongoDB() {
        const options: MongoClientOptions = {
            reconnectInterval: 1000,
            reconnectTries: Number.MAX_VALUE
        };

        try {
            const client = new MongoClient('uri-goes-here', options);
            await client.connect();
            this.db = client.db('dbname');
        } catch (err) {
            console.error(err, 'MongoDB connection failed.');
        }
    }

    async insert(doc: any) {
        if (this.db) {
            try {
                await this.db.collection('collection').insertOne(doc);
            } catch (err) {
                console.error(err, 'Something went wrong.');
            }
        }
    }
}

Method 2: Try-catch Retry

If you want more granular support on trying to reconnect, you can use a try-catch with a while loop. For example, you may want to log an error when it has to reconnect or you want to do different things based on the type of error. This will also allow you to retry depending on more conditions than just the standard ones included with the driver. The insert method can be changed to the following:

async insert(doc: any) {
    if (this.db) {
        let isInserted = false;

        while (isInserted === false) {
            try {
                await this.db.collection('collection').insertOne(doc);
                isInserted = true;
            } catch (err) {
                // Add custom error handling if desired
                console.error(err, 'Attempting to retry insert.');

                try {
                    await this.connectToMongoDB();
                } catch {
                    // Do something if this fails as well
                }
            }
        }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLewView Question on Stackoverflow
Solution 1 - node.jsPeter LyonsView Answer on Stackoverflow
Solution 2 - node.jsHenry BothinView Answer on Stackoverflow
Solution 3 - node.jsMihir PatelView Answer on Stackoverflow