4

I've started using the Q Promise package in a simple node.js application. So I'm interested in how I can close the db connection after all promise sequence is complete.

Example:

var toDbConnectionString = function(dbSettings) {
    return "mongodb://" +
        dbSettings.user + ":" +
        dbSettings.password + "@" +
        dbSettings.url;
};

var connectionString = toDbConnectionString(dbSettings);

Q.nfcall(
    MongoClient.connect,
    toDbConnectionString(dbSettings))
.then(function(db) {
    return Q.ninvoke(db, "collectionNames");
})
.then(function(collections) {
    console.log(collections);
})
.catch(function() {
    console.log(arguments);
});

I want to close the connection after displaying the collection names but there's no db context in this anonymous function.

Is there the way how to handle such cases with the promise pattern?

shadeglare
  • 7,006
  • 7
  • 47
  • 59
  • Why not capture the value of `db` and use it in the final step? – WiredPrairie Oct 01 '13 at 11:03
  • I can use this solution but maybe there's a more elegant way. – shadeglare Oct 01 '13 at 14:20
  • Since you should generally have only one connection to the DB per Node instance, it certainly would be expected. Further, you've got to consider that normally you'll need to use it in other places in your code, so it will need to be accessible. For example, what if you wanted to later count the number of documents per collection (using their collection names)? – WiredPrairie Oct 01 '13 at 14:41
  • You may well be interested in [mongojs](https://npmjs.org/package/mongojs) which offers a much friendlier API and auto-connects for you and [mongod](https://npmjs.org/package/mongod) which builds on top of that by providing promises instead of callbacks as the API – ForbesLindesay Oct 07 '13 at 22:39

2 Answers2

4

If you don't want to do nesting (I certainly don't...) then you can just do like so:

var toDbConnectionString = function(dbSettings) {
    return "mongodb://" +
        dbSettings.user + ":" +
        dbSettings.password + "@" +
        dbSettings.url;
};

var connectionString = toDbConnectionString(dbSettings);
var db;

Q.nfcall(
    MongoClient.connect,
    toDbConnectionString(dbSettings))
.then(function(_db) {
    db = _db;
    return Q.ninvoke(db, "collectionNames");
})
.then(function(collections) {
    console.log(collections);
})
.catch(function() {
    console.log(arguments);
})
.finally(function() {
    if (db) db.close();
});
Esailija
  • 138,174
  • 23
  • 272
  • 326
3

You can nest then-callbacks arbitrarily. It's getting closer to the pyramid of doom, yes, but it's the only way to keep arguments in scope. In your case:

Q.nfcall(
    MongoClient.connect,
    toDbConnectionString(dbSettings))
.then(function(db) {
    return Q.ninvoke(db, "collectionNames")
    .then(function(collections) {
        console.log(collections);
    }).finally(function() {
        db.close();
    });
})
.catch(console.log.bind(console));

However, notice that you usually wouldn't connect and close too often.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375