0

I created a function to convert JSON in CSV. However JSON.parse is returning undefined. Please can someone help.

function JSONtoCSVConverter(JSONDataPath, showLabels) {
  var JSONData = fs.readFile(JSONDataPath, "utf-8", (err, fileContent) => {
    if (err) {
      console.log(err);
    } else {
      console.log(fileContent);
      JSON.parse(fileContent.toString().trim());
    }
  });

  console.log(JSONData);

  if (showLabels) {
    console.log(JSONData.slice(1, JSONData.length));
    var rowsOfDataArray = Object.keys(JSONData[0]);
    var rowsOfData = rowsOfDataArray.join(",") + "\n";
  }

  JSONData.forEach((object) => {
    var cellsOfDataArray = Object.values(object);
    cellsOfData = cellsOfDataArray.join(",") + "\n";
  });

  var csv = rowsOfData + "\n" + cellsOfData;
  return csv;
}

However, the error I have received is:

undefined TypeError: Cannot read properties of undefined (reading 'slice') at JSONtoCSVConverter (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\routes\reports.js:45:26) at C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\routes\reports.js:26:7 at Layer.handle [as handle_request] (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\layer.js:95:5) at next (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\route.js:144:13) at Route.dispatch (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\route.js:114:3) at Layer.handle [as handle_request] (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\layer.js:95:5) at C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\index.js:284:15 at Function.process_params (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\index.js:346:12) at next (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\express\lib\router\index.js:280:10) at urlencodedParser (C:\Users\harsh\OneDrive\Documents\Visual Studio 2022\Web Development\contactStoreApp\node_modules\body-parser\lib\types\urlencoded.js:91:7)

4
  • readFile is async so you won't be immediately able to log the result of the read like that which is why it's undefined. Commented Jan 29, 2023 at 6:54
  • 1
    And just to be clear, when @Andy says it's async they don't mean that it's an async function (see my answer below). It's async in the fact that's its doing work asynchronously. Commented Jan 29, 2023 at 7:04
  • A promise version of readFile was added in version 10. Which may help. Commented Jan 29, 2023 at 7:14
  • I think the mistake is, in your readFile's callback function you have parsed the data. But you have not returned the data. That will cause for getting undefined. return the parsed data. Or else the issues happen because of async, use the readFileSync method. Commented Jan 29, 2023 at 7:26

1 Answer 1

1

JSON.parse returns undefined or fs.readFile returns undefined? fs.readFile is not supposed to return anything

If you want to properly use the result of fs.readFile, you must put the rest of the code in the callback like so:

function JSONtoCSVConverter(JSONDataPath, showLabels) {
    fs.readFile(JSONDataPath, "utf-8", (err, fileContent) => {
        if (err) {
            console.log(err);
        } else {
            console.log(fileContent);
            var JSONData = JSON.parse(fileContent.toString().trim());
            console.log(JSONData);

            if (showLabels) {
                console.log(JSONData.slice(1, JSONData.length));
                var rowsOfDataArray = Object.keys(JSONData[0]);
                var rowsOfData = rowsOfDataArray.join(",") + "\n";
            }

            JSONData.forEach((object) => {
                var cellsOfDataArray = Object.values(object);
                cellsOfData = cellsOfDataArray.join(",") + "\n";
            });

            var csv = rowsOfData + "\n" + cellsOfData;
            console.log(csv)
        }
    });
}

You might have noticed, this is quite messy - this sort of pattern has been dubbed callback hell, and is an older-style of programming in JavaScript when using non-blocking APIs. You will also have noticed that I'm not returning the variable csv - to do that, you must pass a callback function to JSONtoCSVConverter as a third parameter.

Here is an example of doing that (it is called the callback pattern).

function JSONtoCSVConverter(JSONDataPath, cb) {
    fs.readFile(JSONDataPath, "utf-8", (err, fileContent) => {
        if (err) {
            cb(err, undefined);
        } else {
            var JSONData = JSON.parse(fileContent.toString().trim());
            cb(null, JSONData);
        }
    });
}

// use the function like this:
JSONtoCSVConverter('./file.json', function(err, data) {
  if (err) {
    console.error(err);  
  } else {
    console.log('here is JSON data:')
    console.log(data);
  }
});

But, there is a much better solution.

A better solution involves using promises. Recent version of NodeJS have Promise-based APIs (ex. see fs.promises.readFile that allow you to use them like so:

const fs = require('fs')

async function JSONtoCSVConverter(JSONDataPath, showLabels) {
    var fileContent = await fs.promises.readFile(JSONDataPath, "utf-8")
    console.log(fileContent);
    var JSONData = JSON.parse(fileContent.toString().trim());
    console.log(JSONData);

    if (showLabels) {
        console.log(JSONData.slice(1, JSONData.length));
        var rowsOfDataArray = Object.keys(JSONData[0]);
        var rowsOfData = rowsOfDataArray.join(",") + "\n";
    }

    JSONData.forEach((object) => {
        var cellsOfDataArray = Object.values(object);
        cellsOfData = cellsOfDataArray.join(",") + "\n";
    });

    var csv = rowsOfData + "\n" + cellsOfData;
    return csv;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.