mongobird

0.2.0 • Public • Published

NPM Version Build Status Coverage Status Dependencies Unicorn approved


Stories in Accepted Stories in In%20Progress Stories in Please%20Review


mongobird

Bluebird aware mongoDB driver.

installation

Install the module via npm:

npm install mongobird

usage

This simple example connects to a mongoDB instance, gets a specific database and collections and uses this collection to add data and assert that it worked:

var mongobird = require('mongobird'),
    connectionString,
    connection,
    anyDb,
    usersCollection;
 
// The connection string specifies which mongoDB instance should be used
connectionString = 'mongodb://localhost';
 
// Create a connection representation using a connection string
connection = mongobird.connect(connectionString);
 
// Get a representation for any database through the mongoDB instance from above
anyDb = connection.getDb('anyDb');
 
// Get any collection through this database representation
usersCollection = anyDb.getCollection('users');
 
function logAddedUser(user) {
    console.log('Added user ' + user.username);
}
 
function countUser(username) {
    return usersCollection.count({ username: username });
}
 
// Note that all the methods used before this were working lazily - they did not really connect to any database
usersCollection.insert({ username: 'anyUser' })
    .tap(logAddedUser)
    .then(countUser.bind(null, 'anyUser')
    .then(function (count) {
        if (count !== 1) {
            throw new Error('User was not added correctly or exists more than once');
        }
    })
    .catch(function(error) {
        console.log('Handle errors or rethrow them if you are not able to');
    });

As mentioned above, it is important to understand, that the database and collection representations are not connecting to any specific database or collection before they are really used (e.g. for inserting data). One consequence of this is that errors accessing these databases or collection (e.g. for not existing databases) will be thrown later when the collection or database are really used.

See the more detailed "explained example" below for a better understanding how everything works.

explained example

This is a more complex example. See the notes below it to understand how it works internally.

'use strict';
 
var mongobird = require('mongobird'),
    connectionString = 'mongodb://localhost',
    connection = mongobird.connect(connectionString),
    anyDb = connection.getDb('anyDb'),
    usersCollection = anyDb.getCollection('users'),
    defaultUser = { username: 'anyUser' },
    demoFinishedMessage = 'Demo finished succesfully. Have fun using mongobird';
 
function findDefaultUser() {
    return usersCollection.findOne(defaultUser);
}
 
function assertDefaultUserDoesNotExist(user) {
    if (user) {
        throw new Error('Default user already exists');
    }
}
 
function removeUser(user) {
    console.log('Removing user:', user);
 
    return usersCollection.remove({ username: user.username  });
}
 
module.exports = function () {
    return usersCollection.remove({})
        .then(findDefaultUser)
        .then(assertDefaultUserDoesNotExist)
        .then(usersCollection.insert.bind(null, defaultUser))
        .tap(function (addedUsers) {
            if (addedUsers.length !== 1) {
                throw new Error('Not the right amount of users were added');
            } else if (addedUsers[0].username !== defaultUser.username) {
                throw new Error('Added user was not the default user');
            }
 
            console.log('Added default user:', defaultUser.username);
        })
        .then(findDefaultUser)
        .then(function (user) {
            if (!user) {
                throw new Error('Default user does not exist');
            }
 
            return user;
        })
        .then(removeUser)
        .then(function () {
            throw new Error('Something bad happened');
        })
        .then(console.log.bind(null, 'This is not executed if there is an uncaught error'))
        .catch(console.log.bind(null, 'Catching error'))
        .then(console.log.bind(null, 'Error was handled in last catch step'))
        .return(demoFinishedMessage)
        .finally(function () {
            // E.g. close the database connection
        });
};
  1. Create a connection representation using the connect method providing a valid connection string (as specified in the mongoDB documentation about connection strings

    connection = mongobird.connect(connectionString);

    The connect method is a synchronous function. The reason for this is that mongobird connects to mongodb instances lazily and caches the used database connections once they are established.

  2. The returned connection object has the important method getDb which takes a database name and returns a database representation. The method works synchronous and does not connect to the database instantly but saves only the required data to connect to it later.

    anyDb = connection.getDb('anyDb');
  3. This returned database representation can be used to work on mongoDB collections. All collection methods provided by the native mongoDB driver are available and return bluebird Promises. Using one of these methods triggers a real connection to the specified mongo database.

    usersCollection = anyDb.getCollection('users');
  4. The most interesting part happens on this collection representation - some of the more common mongoDB methods are called and all is done using promises

    1. See the general bluebird documentation to learn more about promises in general and how bluebird promises help you writing better readable, understandable and good-looking (in the opinionated view of the creators of this library) way

    2. Read the more specific bluebird api documentation to get used more specifically to the bluebird methods. E.g. you can find documentation on the very useful methods Promise.tap and Promise.try that were used in the example above

    3. One further very good read recommendation is the documentation about promise anti-patterns

api

  • The mongobird.connect method provides a connection representation
connection = mongobird.connect(connectionString);
  • This connection representation can be used to get a database representation
database = connection.getDb(databaseName);
  • This database representations can be used to get collection representations
collection = database.getCollection(collectionName);
  • These collection representations are a central part of mongobird (as they are in the native mongoDB driver). They offer all collection methods provided by the native mongoDB driver with one difference: The methods in the native driver rely on callbacks to handle what is done once they are finished. As mongobird works with promises this looks differently for them. Examples:

    • insert: Instead of calling collection.insert(document, callback)

      ```js` collection.insert(document) .then(function (result) { ... }) .catch(function (error) { ... });

      
      
      
    • find:

      collection.find(document)
          .then(function(foundDocuments) { ... } )
          .catch(function (error) { ... });
    • remove:

      collection.remove(document)
          .then(function (result) { ... })
          .catch(function (error) { ... });

core concept and technology stack

This project is in a very early state and many planned features are missing for now.

Nevertheless there is some interesting additional information:

  • The core concepts were discussed and can be found in this issue
  • The technology stack was discussed and can be found in this issue

Package Sidebar

Install

npm i mongobird

Weekly Downloads

0

Version

0.2.0

License

MIT

Last publish

Collaborators

  • lo1tuma
  • lxanders