3

For organization purposes I'm separating my source code into modules, for example I have the user module on my node.js app which is responsable for retrieving user information from a MongoDB database. I'm doing something like this:

var mongo = require("mongodb"),
    Server = mongo.Server,
    Db = mongo.Db;

var server = new Server("localhost", 27017, { auto_reconnect: true });
var db = new Db("users", server);

module.exports = {
    login: function(user, pass, callback) {
        var reg_result = null;

        db.open(function (err, db) {
            if(!err) {
                db.collection("users", function(err, collection) {
                    collection.findOne(
                        {
                            "username": user,
                            "password": pass
                        },
                        function(err, item) {
                            if(!err) {
                                reg_result = item;
                            } else {
                                reg_result = "error";
                            }
                        }
                    );
                });
            } else {
                reg_result = "error";
                console.log("ERROR: " + err);
            }
        });

        callback(reg_result);
    }
}

And executing it on my test script like this:

var user = require("./user.js");

user.log("test", "test", function(msg) {
    console.log(msg);
});

It does the database operation and retrieves the value, but every time it only returns null, when I don't initialize the reg_result variable it returns undefined. What should I do to correct this?

I debugged using console.log on the user.js and the item was outputted, but I want to have the callback so I can use the item on other sources, like my test script

Nathan Campos
  • 28,769
  • 59
  • 194
  • 300

1 Answers1

6

You are calling the callback function right away, but going to the db takes time and is therefore done asynchronously. Instead, call your callback at the appropriate time using the result argument of the function passed as the last parameter to the .findOne() function. The callback should get an error argument and a result argument:

login: function(user, pass, callback) {
    db.open(function (err, db) {
        if(!err) {
            db.collection("users", function(err, collection) {
                collection.findOne(
                    {
                        "username": user,
                        "password": pass
                    },
                    function(err, item) {
                        if(!err) {
                            callback(null,item);
                        } else {
                            callback("error");
                        }
                    }
                );
            });
        } else {
            callback("error",null);
        }
    });
}


user.login("test", "test", function(err,msg) {
    if( err ) {
      //error occured above;
    } else {
      //success
      console.log(msg);
    }
});

this is just pulling the same pattern through that the mongodb-driver is using. hope it helps.

Ryan Shripat
  • 5,574
  • 6
  • 49
  • 77
mindandmedia
  • 6,800
  • 1
  • 24
  • 33
  • Thanks very much, it works perfectly! I'm moving from pure jQuery mobile apps using Phonegap to node.js so it's a bit difficult some times to get used to the async on node. **:)** – Nathan Campos Mar 16 '12 at 20:15