/ node.js

Using the new mongoose connect method - the right way

This is gonna be a quicky about some headache introduced in mongoose 4.11.x.

The headache

So, you've updated your Node.JS project to the latest mongoose and suddenly you notice this strange error appearing on the console log:

DeprecationWarning: `open()` is deprecated in mongoose >= 4.11.0, use `openUri()` instead, or set the `useMongoClient` option if using `connect()` or `createConnection()`. See http://mongoosejs.com/docs/connections.html#use-mongo-client

Db.prototype.authenticate method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials

The reason

Apparently, due to a planned deprecation of an API in the upcoming mongoDB 3.6, mongoose will need a complete overhaul of its connection mechanism.
This error message is not the result of something you're doing wrong (as of yet), but rather of an issue with the way mongoose is handling things internally.

The aftermath

People trying to follow the instructions on the error message were successful in making it disappear but were then faced with not being able to initiate their models.
The most suggested fix seemed to be to revert to mongoose 4.10.8.

More reasons

The later issue is due to a bug in the way mongoose buffers requests. Mongoose' database connection is, as it should be, an asynchronous operation. When using mongoose you can use your models right away after requesting a connection due to the fact that mongoose buffers database requests when it's still trying to initiate a connection.
This was broken in 4.11.0, to be fixed later on 4.11.2.

TL;DR + fixes

When facing this error message you may either:

  1. Revert to 4.10.8.
  2. Upgrade to the latest version and ignore the message for now. MongoDB 3.6 is a long way down the road and there are no breaking changes expected in any mongoose 4.x.
  3. Do the right thing: Upgrade to the latest mongoose version and update your connection code. Here is a module that does just that:
var mongoose = require('mongoose');

module.exports.connect = function(mongoUri, promiseLib){
    //mongoUri should be in the form of "mongodb://user:pass@url:port/dbname"

    promiseLib = promiseLib || global.Promise;

    //mongoose' Promise library is deprecated, so we need to provide our own.
    mongoose.Promise = promiseLib;
    var mongoDB = mongoose.connect(mongoUri, {
        useMongoClient: true,
        promiseLibrary: promiseLib // Deprecation issue again
    });

    mongoDB
        .then(db => {
            console.log('Mongodb has been connected');
        })
        .catch(err => {
            console.log('Error while trying to connect with mongodb');
            throw err;
        });

    // Even though it's a promise, no need to worry about creating models immediately, as mongoose buffers requests until a connection is made

    return mongoDB
};