Basically, when I just run csvtojson module on node.js without any code, it works perfectly. But once I put it into the function, it just comes out with undefined even though my file path is still there.
Js code:
var Converter = require("csvtojson").Converter;
// create a new converter object
var converter = new Converter({});
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/myproject';
// call the fromFile function which takes in the path to your
// csv file as well as a callback function
var woops;
var createNewEntries = function(db, woops, callback) {
converter.fromFile("./NTA-SAM-Inventory-List-Security-Management-
New_2017.csv",function(err, result){
// if an error has occured then handle it
if(err){
console.log("An Error Has Occured");
console.log(err);
}
// the result of the conversion
console.log(result);
console.log('ohhhhh');
woops=result;
});
console.log(woops);
};
MongoClient.connect(url, function(err, db) {
if(err) {
console.log(err);
}
setTimeout(function(){
createNewEntries(db, woops, function(){
if(err)
throw err;
else{
console.log(woops);
}
db.close();
});
},2000);
});
This is just testing out whether it converts inside a function and it just shows
undefined
[]
ohhhhh
without converting at all when in a function. So exactly what did I do wrong. By right it should have convert after calling the function. Does it have to do with my code executing before the function ? I already put a setTimeout just to give it some time to do so I assume it shouldn't have to do with the order of my code. Thanks in advance!
You should try below code for your file name:
__dirname + "/NTA-SAM-Inventory-List-Security-Management-
New_2017.csv"
Replace your code for converter.fromFile() , Now your code would be like that:
converter.fromFile(__dirname + "/NTA-SAM-Inventory-List-Security-Management-
New_2017.csv" ,function(err, result){
// if an error has occured then handle it
if(err){
console.log("An Error Has Occured");
console.log(err);
}
// the result of the conversion
console.log(result);
console.log('ohhhhh');
woops=result;
MongoClient.connect(url, function(err, db) {
if(err) {
console.log(err);
}
setTimeout(function(){
createNewEntries(db, woops, function(){
if(err)
throw err;
else{
console.log(woops);
}
db.close();
});
},2000);
});
});
Hope it will work for you.
If the above code are not wouking then try below code with fast-csv module:
var fcsv = require('fast-csv');
var fs = require('fs');
/**
* Get the records from csv
*/
var writeZipCodes = function () {
var stream = fs.createReadStream(__dirname + "/NTA-SAM-Inventory-List-Security-Management-New_2017.csv");
fcsv
.fromStream(stream, { headers: true }) // headers for columns
.on("data", function (data) {
console.log(data);
var woops=data;
MongoClient.connect(url, function(err, db) {
if(err) {
console.log(err);
}
setTimeout(function(){
createNewEntries(db, woops, function(){
if(err)
throw err;
else{
console.log(woops);
}
db.close();
});
},2000);
});
})
.on("end", function () {
console.log("done");
});
}
writeZipCodes();
According to your output,
undefined
[]
ohhhhh
var woops;
var createNewEntries = function(db, woops, callback) {
converter.fromFile("./NTA-SAM-Inventory-List-Security-Management-
New_2017.csv",function(err, result){
// if an error has occured then handle it
if(err){
console.log("An Error Has Occured");
console.log(err);
}
// the result of the conversion
console.log(result); // This is getting printed second
console.log('ohhhhh'); // This is getting printed third
woops=result;
});
console.log(woops); // This is getting printed first
};
MongoClient.connect(url, function(err, db) {
if(err) {
console.log(err);
}
setTimeout(function(){
createNewEntries(db, woops, function(){
if(err)
throw err;
else{
console.log(woops); // This is useless!
}
db.close();
});
},2000);
});
You can clearly see this as woops variable is just declared so it must be having undefined value. And something before ohhhhh must be the result variable.
Now, this definitely means that at least the woops variable is not getting printed after ohhhh or rather, the createNewEntries is getting executed or is returning the result after console.log(woops) is being executed which that means your setTimeout()'s time is not sufficient.
And why are you even using the callback and passing it a function when you're not even using it??? Use this instead-
var woops;
var createNewEntries = function(db, woops) {
converter.fromFile("./NTA-SAM-Inventory-List-Security-Management-
New_2017.csv",function(err, result){
// if an error has occured then handle it
if(err){
console.log("An Error Has Occured");
console.log(err);
}
// the result of the conversion
console.log(result);
console.log('ohhhhh');
woops=result;
}).then(console.log(woops));
};
MongoClient.connect(url, function(err, db) {
if(err) {
console.log(err);
}
createNewEntries(db, woops);
});
Related
I have the following code which I'm using to learn how to transition from callbacks, through to async, then moving onto promises and finally await.
For the first time, I'm really struggling to understand why I get nothing at all returned to the console.
I have several logging events in place, but these never trigger inside the code, and non of the errors are thrown / exceptions raised.
I have put in additional logging outside the functions to demonstrate that the files running when requesting eg, nodemon app.js from the terminal. However, the terminal hangs on 'starting'.
What am I doing wrong?
In addition to the code here, I have tried extensively wrapping different parts in try / catch blocks, but nothing is ever returned.
index.js:
const mysql = require('mysql');
const async = require('async');
const dbConfig = require('./db');
const employees = require('./employees');
async.series(
[
function(callback) {
mysql.createConnection(dbConfig, function(err) {
callback(err);
});
},
function(callback) {
employees.getEmployee(101, function(err, emp) {
if (err) {
callback(err);
return;
}
console.log(emp);
});
}
],
function(err) {
if (err) {
console.log(err);
}
}
);
employees.js:
const mysql = require('mysql');
const async = require('async');
function getEmployee(empId, getEmployeeCallback) {
async.waterfall(
[
function(callback) {
mysql.createConnection(function(err, conn) {
if (err) {
console.log('Error getting connection', err);
} else {
console.log('Connected to database');
}
callback(err, conn);
});
},
function(conn, callback) {
conn.execute(
`select *
from employees`,
function(err, result) {
if (err) {
console.log('Error executing query', err);
} else {
console.log('Query executed');
}
callback(err, conn, result);
}
);
}
],
function(err, conn, result) {
if (err) {
getEmployeeCallback(err);
} else {
getEmployeeCallback(null, result.rows[0]);
}
// If error getting conn, no need to close.
if (conn) {
conn.close(function(err) {
if (err) {
console.log('Error closing connection', err);
} else {
console.log('Connection closed');
}
});
}
}
);
}
module.exports.getEmployee = getEmployee;
db.js:
var mysql = require('mysql');
var connection = mysql.createConnection({
host:'localhost',
user:'developer',
password:'superseceretpassword',
database:'testing'
});
connection.connect(function(err) {
if (err) throw err;
});
module.exports = connection;
I have a function that downloads the user input(currently named app.json) from browser(client) to the server
function downloadUpdate(callback) {
//Using formidable node package for downloading user input to server
var form = new formidable.IncomingForm();
form.on('fileBegin', function(name, file) {
file.path = "app.json";
});
form.parse(req, function(err, fields, files) {
res.writeHead(200, {
'content-type': 'text/plain'
});
res.write('received upload:\n\n');
res.end(util.inspect({
fields: fields,
files: files
}));
});
form.on('end', function() {
callback(null);
});
}
I have another function that takes the file downloaded above and converts it into required format(final.json) something like this.
function UpdateCode(callback) {
var obj = fs.readFileSync('app.json', 'utf8');
console.log(abc); //Im getting undefined here
var object = JSON.parse(obj);
var data2 = [];
for (var j = 0; j < object.length; j++) {
if (object[j].value == `${abc}`) {
data2.push(object[j]);
}
}
console.log(data2);
fs.appendFile('final.json', JSON.stringify(data2), function(err) {
if (err) throw err;
console.log('Saved!');
callback(null);
});
}
I used async series function to make them run in an order like this
async.series([
downloadUpload,
UpdateCode
], function(err, result) {
if (err) throw err;
else {
console.log(result);
}
});
All of this code is inside a post request. I'm getting abc from the server
app.post('/', function(req,res){
var abc = req.body.abc;
console.log(abc); //I'm getting abc here
function downloadfile(callback){
//here goes the downloadfile definition
}
function UpdateCode(){
//upload code function
}
//now i call async.series method
async.series([
downloadUpload,
UpdateCode
], function(err, result) {
if (err) throw err;
else {
console.log(result);
}
});
});
the thing is the value of abc is not going to function UploadCode and when I console log abc, I get undefined. Where am I going wrong?
I am writing this code as a project for a customer
and when i go to a show route i got this 500 internal server error
http.get('/files/:id', function(req, res) {
var vid;
var pap;
Videos.find({}, function(err, videos) {
if (err) {
console.log(err);
} else {
vid = videos;
}
});
Papers.find({}, function(err, file) {
if (err) {
console.log(err);
} else {
pap = file;
}
});
Material.findById(req.params.id, function(err, found) {
if (err) {
console.log(err);
} else {
res.render('files', {
file: pap,
video: vid,
current: found
});
}
});
});
this is my show route code.
Note : if i reload the page the error is gone and the page open.
The reason is you need to wait for all the database queries to finish before rendering. In your code, it is possible for the page to render before the other two queries have completed and returned their data. The good news is that Mongoose supports Promises for asynchronous functions.
http.get('/files/:id', function(req, res) {
Promise.all([
Videos.find({}).exec(),
Papers.find({}).exec(),
Material.findById(req.params.id).exec()
]).then( ([video, paper, material]) => {
res.render('files', {
file: paper,
video: video,
current: material
});
}).catch( error => console.log(error) );
});
The functions you're using with Mongoose are asynchronous in nature; the variables vid and pap are not initialized when you run res.render. When you attempt to use those variables in your frontend (template like Jade, Handlebars EJS, I don't know what you're using), they are undefined, and subsequently cause the 500 error. You'll need to run the functions such that the results of all Mongoose queries are available to res.render when it runs; either using an async NodeJS library, or calling each function within one another and then calling res.render at the end.
Solution 1: Using async Node module
var async = require('async');
async.parallel([
// Each function in this array will execute in parallel
// The callback function is executed once all functions in the array complete
function (cb) {
Videos.find({}, function(err, videos) {
if (err) {
return cb(err);
} else {
return cb(null, videos);
}
});
},
function (cb) {
Papers.find({}, function(err, papers) {
if (err) {
return cb(err);
} else {
return cb(null, papers);
}
});
},
function (cb) {
Material.findById(req.params.id, function(err, found) {
if (err) {
return cb(err);
} else {
return cb(null, found);
}
});
}
], function (err, results) {
if (err) {
// If any function returns an error
// (first argument), it will be here
console.log(err);
}
else {
// Even though the functions complete asynchronously,
// the order in which they are declared in the array
// will correspond to the position in the array
// if it returns anything as a second argument.
var videos = results[0];
var files = results[1];
var found = results[2];
res.render('files', {
file: files,
video: videos,
current: found
});
}
});
Solution 2: Nested Callbacks
Videos.find({}, function(err, videos) {
var vid = videos;
if (err) {
console.log(err);
} else {
Papers.find({}, function(err, file) {
var pap = file;
if (err) {
console.log(err);
} else {
Material.findById(req.params.id, function(err, found) {
if (err) {
console.log(err);
} else {
res.render('files', {
file: pap,
video: vid,
current: found
});
}
});
}
});
}
});
To catch errors I have written if-else blocks in every function which looks bad. Please suggest a better way to handle errors in async node
async.waterfall([
function(callback){
fnOne.GetOne(req, res,function(err,result) {
if(err){
console.error("Controller : fnOne",err);
callback(err,null);
}
else{
var fnOne = result;
callback(null, fnOne);
}
})
},
function(fnOne, callback){
fnTwo.two(fnOne,function(err,result) {
if(err) {
console.error(err);
callback(err,null);
}
else{
callback(null, context);
}
})
}
], function (err, result) {
if(err){
console.error("Controller waterfall Error" , err);
res.send("Error in serving request.");
}
});
You can pass the error to async and catch it in the callback
async.waterfall([
function (callback) {
fnOne.GetOne(req, res, callback); // err and result is passed in callback
}, // as it's "function(err, result)"
function (fnOne, callback) { // the same as the arguments for the
fnTwo.two(fnOne, callback); // callback function
}
], function (err, result) {
if (err) {
console.error("Error :", err);
res.send("Error in serving request.");
}else{
res.end("A-OK");
}
});
You do too much stuff
Waterfall already have an internal error management.
callback(err, [results]) - An optional callback to run once all the
functions have completed. This will be passed the results of the last
task's callback.
Try this
async.waterfall([
function(callback){
fnOne.GetOne(req,res, callback)
},
function(fnOne, callback){
fnTwo.two(fnOne,callback) {
}
], function (err, result) {
if(err){
console.error("Controller waterfall Error" , err);
res.send("Error in serving request.");
}
});
async.each(files, (file, callback) => {
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(file.file.originalname);
const blobStream = blob.createWriteStream();
blobStream.on('error', (err) => {
callback(err);
});
blobStream.on('finish', () => {
// The public URL can be used to directly access the file via HTTP.
Storage.bucket(BUCKET_NAME)
.file(blob.name)
.move(body.email + '_' + file.dir + '.' + blob.name.split('.').pop())
.then((e) => {
body[file.dir] = format(`https://storage.googleapis.com/${BUCKET_NAME}/${e[0].name}`)
callback();
})
.catch(err => {
console.error('ERROR: ', err);
});
});
blobStream.end(file.file.buffer);
}, (err) => {
if (err) {
console.error(err);
return res.status(422).send({error: true, data: {message: "An error occured. Please fill all fields and try again"}});
}
// save to db
});
Trying a few node.js filesystem checks (to confirm if environment is functioning correctly)
When I write my fs.unlink or fs.unlinkSync outside of Mocha it deletes the file as expected:
var fs = require('fs');
var newFile = new Date().getTime() +".txt";
fs.writeFile(newFile, "hello!", function (err) {
if (err) console.log(err);
// console.log("Created file: "+newFile);
fs.readdir(__dirname, function(err, list) {
// console.log(list)
console.log(list.indexOf(newFile) > -1)
fs.unlinkSync(newFile);
console.log('successfully deleted '+newFile);
// console.log("Deleted: "+newFile)
fs.readdir(__dirname, function(err, list) {
if (err) throw err;
console.log(list.indexOf(newFile) === -1);
});
});
});
But when I try the exact same code from inside a mocha test it does not delete the file...
var chai = require('chai');
var assert = chai.assert;
var fs = require('fs');
describe('Node.js Environment Checks', function(){
describe('Basic IO', function(){
it('CREATE (temporary) file tests create/write access to FS', function(){
// setup
var newFile = new Date().getTime() +".txt";
fs.writeFile(newFile, "hello!", function (err) {
if (err) console.log(err);
// console.log("Created file: "+newFile);
fs.readdir(__dirname, function(err, list) {
// console.log(list)
assert.isTrue(list.indexOf(newFile) > -1)
fs.unlinkSync(newFile);
console.log('successfully deleted '+newFile);
// console.log("Deleted: "+newFile)
fs.readdir(__dirname, function(err, list) {
if (err) throw err;
assert.isTrue(list.indexOf(newFile) === -1);
});
});
});
})
})
}) // end node env checks
Am I missing something...?
note: I created an issue on GitHub:
https://github.com/visionmedia/mocha/issues/1058
(If I get a reply there first I will mirror it here)
Use the asynchronous form of testing. Change your it call so that the callback gets the done parameter:
it('CREATE (temporary) file tests create/write access to FS', function(done){
And call it in your innermost async callback:
fs.readdir(__dirname, function(err, list) {
if (err) throw err;
assert.isTrue(list.indexOf(newFile) === -1);
done();
});