0

I am working on a node.js project in which I need to communicate with a mongoDb database. I am currently programming a function to find some data in my db using th node-mongodb-native module. Everything works, but my code looks like a callback in a callback in a callback in a callback...

I created this function to prevent me from using callbacks every time I want to access my database. I now just need to call this function.

module.exports.find = function(query, projection, callback){
    db.open(function(err, db){
        if(err) throw err;
        db.collection('rooms', function(err, collection){
            if(err) throw err;
            collection.find(query, projection, function(err, cursor){
                if (err) throw err;
                cursor.toArray(function(err, find){
                    db.close();
                    callback(err, find);
                });
            });
        });
    });
};

Is there a method to reduce this codeception ?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Maxime
  • 2,192
  • 1
  • 18
  • 23
  • take a look at [async](https://github.com/caolan/async) – go-oleg Jun 27 '13 at 01:17
  • Why you don't declare a variable in your main function and assign db, collection and cursor to them and immediately return from your inner-callbacks! this way you can avoid callback-in-callback. – Boynux Jun 27 '13 at 01:21
  • @Boynux, like this : `var database = db.open(function(err, db){ if(err) throw err; return db; });` ? – Maxime Jun 27 '13 at 01:36

2 Answers2

2

If you just want to know how to cleanup callbacks reasonably and scope db:

module.exports.find = function(query, projection, callback){
    var local_db;

    function db_open(err, db) {
        if(err) throw err;
        local_db = db;
        local_db.collection('rooms', handle_homes_collection);

    }

    function handle_homes_collection(err, collection){
        if(err) throw err;
        collection.find(query, projection, handle_find_query);
    }

    function handle_find_query(err, cursor){
        if (err) throw err;
        cursor.toArray(function(err, find){
            local_db.close();
            callback(err, find);
        });
    }

    db.open(db_open);
};
Mulan
  • 129,518
  • 31
  • 228
  • 259
Matthew Graves
  • 3,226
  • 1
  • 17
  • 20
  • 1
    +1: Giving each function a name is also a very good way of documenting what it does. There is a place for anonymous functions but I think if you're nesting more than one level deep you need to name them ;) – slebetman Jun 27 '13 at 02:01
  • Thank you! It worked! I just needed to change the `db.open` by another variable name (`database.open`) because it returned `Cannot call method 'open' of undefined`, but after this little edit it worked :) – Maxime Jun 27 '13 at 02:06
0

Like this:

module.exports.find = function(query, projection, callback){
    var database;

    db.open(function(err, db_temp){
        if(err) throw err;

        database = db_temp;
    });

    database.collection('rooms', function(err, collection){
        if(err) throw err;
        collection.find(query, projection, function(err, cursor){
            if (err) throw err;
            cursor.toArray(function(err, find){
                db.close();
                callback(err, find);
            });
        });
    });
};
Boynux
  • 5,958
  • 2
  • 21
  • 29
  • That doesn't look much better and relies on `.open` being synchronous – Bergi Jun 27 '13 at 01:50
  • I tester your code and it throws an error : Cannot call method 'open' of undefined. After I changed the `var db;` for `var database` and `database.collection(`, but now ti throws : Cannot call method 'collection' of undefined – Maxime Jun 27 '13 at 01:54
  • oh! sorry, may bad! yes of course, i'll fix it! – Boynux Jun 27 '13 at 01:59
  • Oh, and finally, would you recommend using async.waterfall or this technique? – Maxime Jun 27 '13 at 02:08
  • Sorry, I've no experience with that! Some googling may help :) BTW, you can extend this method to collection too! – Boynux Jun 27 '13 at 02:17
  • 1
    I'll do that, thank you :) – Maxime Jun 27 '13 at 02:20