0

I am trying to return whether a user already exists in a MongoDB. Running console.log within collection.find() prints the correct amount (greater than 0). However, when userExists is called, it always returns false (0).

How do I make Javascript wait for these functions to complete before returning a value? I've read about jQuery's $.Deffered(), but this feels dirty to me, and it didn't work.

function userExists(db, uid){
    var collection = db.get('users');
    var ret = 0;

    collection.find({"uid":uid},{},function(e,docs){
        ret = docs.length
    });

    return ret > 0?true:false;
}
t0mppa
  • 3,983
  • 5
  • 37
  • 48
  • 2
    possible duplicate of [How to return the response from an Ajax call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – vkurchatkin Nov 07 '14 at 19:28

3 Answers3

1

As some have noted, collection.find is asynchronous, so when you reach the next line in userExists (the line where you've got return ret > 0?true:false;), it's too early and the value of ret hasn't been set. Anywhere outside of the callback to collection.find (and any functions it calls in turn), the query hasn't happened yet.

There is (basically) no way to "pause" userExists until after the query, so you need to change your whole approach. What you need is the Continuation Pattern. This means that whatever you're doing with the result of collection.find has to happen in the callback.

I don't know what you're trying to do with ret, so this might mean big changes to how your code is organized. Here's an outline that I hope will give you the general idea:

function processResultAndDisplayToTheUser(ret) {
    //everything that needs to happen after the value of ret is set
    if (ret > 0) {
       doSomething();
    } else {
       doSomethingElse();
    }
}

function userExists(db, uid){
    var collection = db.get('users');

    //ret doesn't exist here

    collection.find({"uid":uid}, {}, function(e,docs){
        var ret = docs.length;

        //ret finally exists, so pass it to a function and use it
        processResultAndDisplayToTheUser(ret);
    });

    //ret doesn't exist here either
}

//ret still doesn't exist here
Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
  • I took the hint from so many posts about asynchronous functions and restructured my code. Will post in a moment. – Alan Helton Nov 07 '14 at 19:56
1

I took the hint and ended up restructuring my code. I created a function addUpdateUser(), did the count there, then ran the addUser() or updateUser() functions accordingly.

addUpdateUser(db, {
    "uid" : uid,
}); 

function addUpdateUser(db, userInfo){
    var collection = db.get('users');

    collection.find({"uid":userInfo.uid},{},function(e,docs){
        if(docs.length > 0){
            updateUser(db, userInfo)
        }else{
            addUser(db, userInfo)
        }
    });
}
0

since collection.find is asynchronous method that doesn't return immediately you need to change your code to,

you can pass a callback function

 function userExists(db, uid,callback){
var collection = db.get('users');


   collection.find({"uid":uid},{},function(e,docs){

    callback(docs.length);
   });

 }

now you can call this userExists function as

      userExists(db, uid,function(ret){
                              //do something here

              })
A.B
  • 20,110
  • 3
  • 37
  • 71
  • 1
    See the other answer, you've made the same mistake. That will not work. – E_net4 Nov 07 '14 at 19:34
  • Ok, that would work now. You can also get rid of the `ret` variable by just passing `docs.length` to the call to `callback`. – E_net4 Nov 07 '14 at 19:39
  • This is that kind of structure I keep seeing everywhere. Is callback() a real JavaScript function? Does callback somehow get routed to ret when userExists is called? Sorry for my inability to wrap my brain around this. – Alan Helton Nov 07 '14 at 20:05
  • In your answer, ret never actually exists til you call userExists(). Where does it come from? – Alan Helton Nov 07 '14 at 20:07
  • actually @HallHelton, not you are passing docs.length to callback function, which you can say anything i wrote it "ret" for your understanding – A.B Nov 07 '14 at 20:10
  • I used the above for another section of my code. I'm blown away. This is very useful. To answer my earlier question, callback is a function. – Alan Helton Nov 07 '14 at 20:29
  • yes callback is a function, you can pass directly or can declare some where else and pass name as parameter – A.B Nov 07 '14 at 20:33