0

I am connecting to S3 and parsing a json file out,
I created a new object called Singer and an array of objects. I would like to use this array of objects outside of the scope of the function

console.log("Loading up the best code ever!!!");

var fs = require('fs');
// Load the SDK for JavaScript
var AWS = require('aws-sdk');
var jsonfile = require('jsonfile')
var Singer = require('./Singer')
// Set the region 
AWS.config.update({ region: "us-west-1" });
var credentials = new AWS.SharedIniFileCredentials();
AWS.config.credentials = credentials;
// Create S3 service object
s3 = new AWS.S3({ apiVersion: '2006-03-01' });
console.log("after S3");


// Create the parameters for calling createBucket
var bucketParams = {
    Bucket: 'pc-backend-exercises',
    Key: 'toSearch.json',
    ResponseContentType: 'application/json'
};
s3.getObject(bucketParams, function (err, data) {
    // Handle any error and exit
    if (err) {
        console.log(err, err.stack); 
        return err;
    }
    var fileContents = data.Body.toString();
    var json = JSON.parse(fileContents);
    console.log(json);

    var singers = [];
    for (var i = 0; i < json.Search.artists.length; i++) {
        var newSinger = new Singer(json.Search.artists[i]);
        singers.push(newSinger);
    }


    console.log('Singers:');
    console.log(singers);


});

console.log('download json file from s3');

this code works fine. I get the output

Loading up the best code ever!!!
after S3
download json file from s3
{ Search: { artists: [ 'Katy', 'Madonna', 'Rihanna', 'Beyonce' ] } }
Singers:
[ Singer { name: 'Katy', songs: [] },
  Singer { name: 'Madonna', songs: [] },
  Singer { name: 'Rihanna', songs: [] },
  Singer { name: 'Beyonce', songs: [] } ]

however what I change my code to pass the array singers by reference it doesn't work.

var singers = [];
s3.getObject(bucketParams, function (err, data, singers) {
    // Handle any error and exit
    if (err) {
        console.log(err, err.stack); 
        return err;
    }
    var fileContents = data.Body.toString();
    var json = JSON.parse(fileContents);
    console.log(json);


    for (var i = 0; i < json.Search.artists.length; i++) {
        var newSinger = new Singer(json.Search.artists[i]);
        singers.push(newSinger);
    }

});

console.log('Singers:');
console.log(singers);


console.log('download json file from s3');

the output is:

Loading up the best code ever!!!
after S3
Singers:
[]
download json file from s3
{ Search: { artists: [ 'Katy', 'Madonna', 'Rihanna', 'Beyonce' ] } }
C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\request.js:31
            throw err;
            ^

    TypeError: Cannot read property 'push' of undefined
        at Response.<anonymous> (C:\Users\gdarmon\Desktop\Node\gili.js:38:17)
        at Request.<anonymous> (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\request.js:364:18)
        at Request.callListeners (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\sequential_executor.js:105:20)
        at Request.emit (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\sequential_executor.js:77:10)
        at Request.emit (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\request.js:683:14)
        at Request.transition (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\request.js:22:10)
        at AcceptorStateMachine.runTo (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\state_machine.js:14:12)
        at C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\state_machine.js:26:10
        at Request.<anonymous> (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\request.js:38:9)
        at Request.<anonymous> (C:\Users\gdarmon\Desktop\Node\node_modules\aws-sdk\lib\request.js:685:12)

Can you please help?

Gilad
  • 6,437
  • 14
  • 61
  • 119

2 Answers2

1

You have two issues here.

The error message

Cannot read property 'push' of undefined

Look here:

s3.getObject(bucketParams, function (err, data, singers) {

singers is undefined because you have defined an argument called singers (which masks the variable in the wider scope). The getObject function, when it calls the anonymous function you pass to it, doesn't give the third argument a value.

I have no idea why you expect it to.

If you remove that argument, then you will have access to the singers variable in the wider scope again.

Order of execution

This is a FAQ. See How do I return the response from an asynchronous call? which is probably in the top 3 targets for "Close as duplicate" on all of Stackoverflow.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
0

The problem is scope of the variables. You have defined same variable name in local as well as global.

Change the local variable name and it should work I have changes as singers1

var singers = [];
s3.getObject(bucketParams, function (err, data, singers1) {
abdulbarik
  • 6,101
  • 5
  • 38
  • 59