0

New to Node and Mongoose here. I am having trouble running my mongoose findOne() query in a synchronous fashion within a function. Here is my code:

exports.read = function(req, res){
    console.log("in articles controller read()");

        //try to get article creatorId and use user providerData
        //name to make fullName
        var userName = "";

        //get article creator id
        User.findOne({ '_id': req.article.creator._id }, function(err, person){
            if(err) { return next(err)};
            if (!person) { return next(new Error('Failed to find user'))};

            console.log("found person");
            //return providerData name 
            userName =  person.providerData.name;


        });

        //assign username value to article creator
        var splitName = userName.split(' ');
        req.article.creator.fullName = userName;
        req.article.creator.firstName = splitName[0] || '';
        req.article.creator.lastName = splitName[1] || '';

    console.log("end of read()";
    res.json(req.article);
};

When I look at my console, I expect to see the logs in the following order:

  1. in articles controller read()
  2. found person
  3. end of read()

But instead, I see in my console:

  1. in articles controller read()
  2. end of read()
  3. found person

I'm assuming that this issue has to probably do with the async nature of node? Basically, I would like to run the findOne() query before assigning values to my req object so that I can actually have something to assign. Please help.

Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
Jason Dinh
  • 109
  • 1
  • 7

2 Answers2

1

Callbacks are async, you need to move your code inside it.

User.findOne({ '_id': req.article.creator._id }, function(err, person){
    if(err) { return next(err)};
    if (!person) { return next(new Error('Failed to find user'))};

    console.log("found person");
    //return providerData name 
    userName =  person.providerData.name;

    //assign username value to article creator
    var splitName = userName.split(' ');
    req.article.creator.fullName = userName;
    req.article.creator.firstName = splitName[0] || '';
    req.article.creator.lastName = splitName[1] || '';

    res.json(req.article);
});
Pier-Luc Gendreau
  • 13,553
  • 4
  • 58
  • 69
0

You are using the Nodejs which is asynchronous and event-driven. So it will call the method in sequence way:

console.log("in articles controller read()");
User.findOne();
console.log("end of read()";

but User.findOne is the database call which is slow, so it call User.findOne and it will go tho then another method call and when they will return the result it will print.

That's by you will get the result as

in articles controller read()
end of read()
found person

For solving this you can use the async.js or you can directly put the value inside the findOne result:

    exports.read = function(req, res){
    console.log("in articles controller read()");

        //try to get article creatorId and use user providerData
        //name to make fullName
        var userName = "";

        //get article creator id
        User.findOne({ '_id': req.article.creator._id }, function(err, person){
            if(err) { return next(err)};
            if (!person) { return next(new Error('Failed to find user'))};

            console.log("found person");
            //return providerData name 
            userName =  person.providerData.name;

            //assign username value to article creator
            var splitName = userName.split(' ');
            req.article.creator.fullName = userName;
            req.article.creator.firstName = splitName[0] || '';
            req.article.creator.lastName = splitName[1] || '';

            console.log("end of read()");
            res.json(req.article);

        });
    }
Community
  • 1
  • 1
Vishnu Mishra
  • 3,683
  • 2
  • 25
  • 36