0

I am new to nodejs. Using bluebird promises to get the response of an array of HTTP API calls, and storing derived results in an ElasticSearch.

Everything is working fine, except I am unable to access the variables within the 'then' function. Below is my code:

Promise.map(bucket_paths, function(path) {
    this.path = path;
    return getJson.getStoreJson(things,path.path);
}, {concurrency:1}).then(function(bucketStats){
    bucketStats.map(function(bucketStat) {   
        var bucket_stats_json = {};
        bucket_stats_json.timestamp = new Date();
        bucket_stats_json.name = path.name ==> NOT WORKING
    });
});

How can I access the path.name variable within the 'then' ? Error says 'path' is undefined.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
user2405589
  • 881
  • 2
  • 14
  • 32
  • 1
    the tabbing on that code is super confusing – Kevin B Apr 02 '18 at 22:07
  • A .then on `getStoreJSON()` would allow you to morph the result to one that includes `path`, then you'll be able to access it later based on how you morphed the result. – Kevin B Apr 02 '18 at 22:09
  • Sorry about the tabs on the code. I didn't get how I can morph the result to include path. I have to wait for the Promise.map to finish since I need all the results at once. Could you show me an example, please? – user2405589 Apr 02 '18 at 22:35
  • 1
    Five different options for solving that question shown in [the answer](https://stackoverflow.com/questions/28714298/how-to-chain-and-share-prior-results-with-promises/28714863#28714863) yours was marked a duplicate of. – jfriend00 Apr 02 '18 at 22:41
  • Why did you just undo most of the code formatting I had just fixed for you? It's still messed up. I had it nice and clear before you tromped over my changes. – jfriend00 Apr 02 '18 at 22:42
  • Yikes. Sorry, I thought I was making it more readable - didn't see you had already done that. – user2405589 Apr 02 '18 at 22:43
  • OK, I put it back. Hopefully the question yours is marked a dup of shows you plenty of options to pick from. – jfriend00 Apr 02 '18 at 22:44
  • FYI, `this.path = path` is wrong here too. I don't know what you were expecting `this` to be, but it's not likely a good place to store your `path` property. – jfriend00 Apr 02 '18 at 22:45
  • Hello @jfriend00 Thanks for the link, but those examples work if you know the exact number of HTTP calls you need to make. In my example, we don't have that information. Which is why I am using the Promise.map function. – user2405589 Apr 02 '18 at 23:40
  • So, I guess it's unclear what you're trying to do then. You have N separate `path` values, one for each item in the `bucket_paths` array. How do you expect to use those later? – jfriend00 Apr 02 '18 at 23:41
  • 1
    OK, I proposed an answer for you. – jfriend00 Apr 02 '18 at 23:48
  • 1
    Also, it's very misleading when you use `json` in the name of a Javascript object or function name. JSON is a plain text format, not a Javascript object so when you confuse the two in your variable naming or function naming, it makes your code very confusing to read. It appears that `getJson.getStoreJson()` returns a Javascript object, not JSON so that seems misnamed. Same with `bucket_stats_json`. That's a Javascript object, not JSON. – jfriend00 Apr 02 '18 at 23:50

1 Answers1

1

The best way to do this is to package the data you need from one part of the promise chain into the resolved value that is sent onto the next part of the chain. In your case with Promise.map(), you're sending an array of data onto the .then() handler so the cleanest way to pass each path down to the next stage is to make it part of each array entry that Promise.map() is resolving. It appears you can just add it to the bucketStat data structure with an extra .then() as show below. When you get the data that corresponds to a path, you then add the path into that data structure so later on when you're walking through all the results, you have the .path property for each object.

You don't show any actual result here so I don't know what you're ultimately trying to end up with, but hopefully you can get the general idea from this.

Also, I switched to Promise.mapSeries() since that's a shortcut when you want concurrency set to 1.

Promise.mapSeries(bucket_paths, function(path) {
    return getJson.getStoreJson(things,path.path).then(bucketStat => {
        // add the path into this item's data so we can get to it later
        bucketStat.path = path;
        return bucketStat;
    });
}).then(function(bucketStats){
    return bucketStats.map(function(bucketStat) {   
        var bucket_stats_json = {};
        bucket_stats_json.timestamp = new Date();
        bucket_stats_json.name = bucketStat.path.name;
        return bucket_status_json;
    });
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Hi @jfriend00 - the part where `bucketStat.path = path;` - The then function does not have access to the path variable. I get the 'path' not defined error again with this. – user2405589 Apr 03 '18 at 02:37
  • 1
    @user2405589 - Yes, it does. It's in the parent scope just fine. This is a nested `.then()` handler which can see parent scope variables like `path`. – jfriend00 Apr 03 '18 at 02:50
  • Thank you so much @jfriend00 !! This solution worked for me, and I hope will help others too. This is a great solution! – user2405589 Apr 03 '18 at 16:10