0

Using Monoskin in Express route I'm doing the following:

router.get(/getbuyerinfo, function(req, res) {

    var data = "data";

    db.collection('buyerRec').find().toArray(function(err, result) {
        if (err) throw err;
        console.log(result);

        db.collection('buyerHistory').find().toArray(function(err, result) {
            if (err) throw err;
            console.log(result);
            console.log(data);
        });
    });
});   

It's actually much deeper. But in an attempt to clean up the deep callbacks, in the most straight forward and quickest manner, even if not the most modern way, I created:

router.get(/getbuyerinfo, getBuyerRec);

function getBuyerRec(req, res) {
    var data = "data";

    db.collection('buyerRec').find().toArray(getBuyerHistory);
}

function getBuyerHistory(err, result) {
    if (err) throw err;
    console.log(result);

    db.collection('buyerHistory').find().toArray(function(err, result) {
        if (err) throw err;
        console.log(result);
        console.log(data);
    });
}

My problem is that 'data' is no longer in scope. The 'data' value came from the Express router.get(). How do I pass 'data' to the getBuyerHistory function so I can use it?

Ric
  • 796
  • 12
  • 28
  • your example shows data still being in scope. – zzzzBov Apr 21 '16 at 20:29
  • @zzzzBov that would be my dream because it is simple. May I ask you to explain your understanding to me? 'data' and the rest of the code is in fact within an Express route, as I will adjust the code to show. So 'data' is not global. How is it within scope within the getBuyerHistory function? – Ric Apr 21 '16 at 22:30
  • 1
    Have a look [over here](http://stackoverflow.com/a/28250687/1048572) - partial application is what you're looking for. Even if done by closure not `bind` or `partial` etc, you can get your nesting down to a maximum of two levels. – Bergi Apr 21 '16 at 22:58
  • @Bergi in your write-up in the link you provided, you were in complete control of the parameters of the functions. It made good sense. But as I am trying to work with Mongoskin code with fixed parameters sets it was still not clear to me as to how I would get 'data' down the line to my last function getBuyerHistory. – Ric Apr 22 '16 at 01:25
  • @Ric: Are you saying you can't control the parameters of `getBuyerHistory`? – Bergi Apr 22 '16 at 02:11
  • @Bergi I can't control the parameters in a db.collection().find().toArray(err, result) statement. ----- I would like to do the equivalent of db.collection('buyerRec').find().toArray(getBuyerHistory(data)); ----- and then in the function below that do: function getBuyerHistory(err, result, data) – Ric Apr 22 '16 at 03:12
  • @Ric: Sure, you can do quite exactly that, it's what the linked answer describes. See zzzzBov's answer for how you'd write it in your specific case – Bergi Apr 22 '16 at 12:04

1 Answers1

1

assuming you have something along the lines of:

(function () {
  var data = "data";

  db.collection('buyerRec').find().toArray(getBuyerHistory);
}());

function getBuyerHistory(err, result) {
    if (err) throw err;
    console.log(result);

    db.collection('buyerHistory').find().toArray(function(err, result) {
        if (err) throw err;
        console.log(result);
        console.log(data);
    });
});

you can create a function that returns a function, and pass data in as a parameter:

function factory(data) {
  return function getBuyerHistory(err, result) {
    ...
  };
}

Which you can then call to create the function you pass to toArray:

(function () {
  var data = "data";

  db.collection('buyerRec').find().toArray(factory(data));
}());

alternatively, if you're not otherwise using this within getBuyerHistory, you could bind data as the context and pass the bound function to toArray:

(function () {
  var data = "data";

  db.collection('buyerRec').find().toArray(getBuyerHistory.bind(data));
}());

alternatively, as @Bergi correctly pointed out, you can add another parameter to getBuyerHistory and use bind without a context:

(function () {
  var data = "data";

  db.collection('buyerRec').find().toArray(getBuyerHistory.bind(null, data));
}());

function getBuyerHistory(data, err, result) {
    ...
}
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • How about `makeBuyerHistoryGetter` instead of `factory`? :-) – Bergi Apr 21 '16 at 22:59
  • `bind` works cleaner if you add a parameter to `getBuyerHistory` and pass nothing for context. – Bergi Apr 21 '16 at 23:00
  • Ok, I don't have a lot of experience. I get it from doing. And doing takes a while. But my code example above, which I have expanded for more context, is very straight forward. The first example, the callback hell example works. The redo, with what I believe brings in lost scope is simple too. These answers seem really contorted, maybe because it is advanced to my experience. Is there not a simple no way to pass the data var down the line and keep the code straight forward. What about @zzzzBov comment that in fact scope is not lost. It seems to me it is. – Ric Apr 22 '16 at 00:45
  • 1
    @Ric, Consider reviewing other questions, such as [this one](http://stackoverflow.com/a/500459/497418) for how variables are scoped in JavaScript. Basically if the variable is in a function or parent function, it's in scope. Your original example had `data` within the same function as `getBuyerHistory`, which meant that `getBuyerHistory` could access that variable. You've since changed your question to show that `data` is not contained in a function that also contains the declaration for `getBuyerHistory`, so at that point you need to use a function to generate a closure. That's how it's done. – zzzzBov Apr 22 '16 at 01:10
  • @zzzzBov Guilty. I had not included the full code at first because I was trying to be brief and did not understand the ramifications of it not being included. :( BTW, your link on scope was very interesting. Valuable to see all the variations together. – Ric Apr 22 '16 at 03:04
  • 1
    @Ric, another good question worth a read is ["How do JavaScript closures work?"](http://stackoverflow.com/a/111111/497418) – zzzzBov Apr 22 '16 at 03:54