nodeJS - Cannot set property of undefined - node.js

i know this question may be asked about 1000 times here but i cant find the error in my script.
I am trying to iterate through 2 arrays to get a name from an city_id and an organisation_id in a each() loop. i would like to write there values to the "mother"-object to get all informations in one place. Here is the code i've written so far:
let express = require('express');
let router = express.Router();
let request = require('request');
let connection = require('../lib/mysql');
router.get('/', function(req, res) {
if(req.session.loggedin === true){
getList((err, finlist) => {
console.log(finlist)
});
} else {
const cssPath = '/stylesheets/style.css'
res.render('login', { cssPath, title: 'Login' });
}
});
function getList(callback) {
var result = [];
connection.query('SELECT * FROM lists ', (err, rows) => {
if(err) throw err;
var r=0;
rows.forEach(function(item) {
result[r] = item;
getCities((err, cty) => {
result[r].city = cty[item.city_id].name;
getOrganisations((err, org) => {
result[r].organisation = org[item.organisation_id].name;
});
callback(result);
});
r++;
});
});
}
function getCities(callBack) {
var result=[];
connection.query('SELECT * FROM cities ', (err, rows) => {
if (err) throw err;
rows.forEach(function (cty) {
result[cty.id] = cty;
});
if (err) {
callBack(err, null);
} else {
callBack(null, result);
}
});
}
function getOrganisations(callBack) {
var result=[];
connection.query('SELECT * FROM organisations ', (err, rows) => {
if(err) throw err;
rows.forEach(function(org) {
result[org.id] = org;
});
if (err) {
callBack(err, null);
} else {
callBack(null, result);
}
});
};
module.exports = router;
I always get the error
TypeError: Cannot set properties of undefined (setting 'city')
at /opt/alarmprocessor/routes/settings.js:53:32
. . .
which is the line result[r].city = cty[item.city_id].name;
King regards for helping me out :)
Tried to set it as an array, as an Object, made console outputs everywhere... seems all to be fine.. Maybe i am too new to NodeJS so it hasnt been clicked in my Head ;D

This error occur because result[r] doesn't exist line 53. It's declared but doesn't "exist" -> it's undefined. If you perform a mere console.log(result[r]); line 52 you will get an undefined, and you can't set properties (like city) to an undefined value.
The quick fix would be to use optional chaining like this:
result[r]?.city = cty[item.city_id].name;
it won't fix your code, it will only stop crashing by ignoring the assignment.

Related

return value not getting logged from module exports

I'm writing a code that uses a library(jsforce) to query on Salesforce and get the records.
Currently, to keep the code clean, I'm separating the index and rest calls file. Here is my code.
var jsforce = require('jsforce');
const uName = 'myId';
const pwd = 'myPwd';
const servKey = 'myKey';
var conn = new jsforce.Connection();
var login = conn.login(uName, pwd, servKey, function (err, res) {
if (err) { return false; }
return true;
});
module.exports = {
myCases: () => {
console.log(`I'm called`);
login.then(() => conn.query(`Select ID, Subject from Case where status='new'`, function (err, openCases) {
if (err) { return console.error(err); }
return openCases;
}));
}
}
and my index file is as below.
const restServices = require('./restServices');
var test = function () {
restServices.myCases((err, data, response) => {
console.log('err')
console.log(err)
console.log('data');
console.log(data);
console.log('response');
console.log(response);
});
}
test();
When I run it, my log prints only I'm called (from restServices.js). but none of the data from my index.js is printed.
also when I add a console.log(openCases), it prints exactly the required data.
please let me know on where am I going wrong in returning the data and how can I fix this.
Thanks
To mycase pass an callback
Example in service.js
Mycase(callback) =>{
// response, err from db then
Callback(err, response)
}
In index.js
Service.mycase((err, response) =>{
Console.log (err, response)
}

Cant set headers after they are sent node.js

I am trying to combine multiple textfiles,convert them in a single zip file using zip archiver.
exports.downloadFilesInZip = function(req, res, next) {
var respObj = {};
var file_names = [];
var projectId = 111;
var file_ids = 11111;
console.log(projectId);
db.getConnection(function (err, connection) {
if (err) {
debug(err);
next(err);
}
else {
var updateQuery = "select data from file_data where file_id IN (?)";
console.log(updateQuery);
connection.query(updateQuery,[file_ids], function (err, results) {
console.log("inside" + updateQuery);
if (err) {
connection.release();
console.log("error" + JSON.stringify(err));
debug(err);
next(err);
}
else {
async.eachSeries(results,function(item,loopCallBack){
var text = "";
console.log("hllllllll");
console.log(item.data);
console.log(JSON.parse(item.data));
document_text = JSON.parse(item.data);
console.log("dssddssdsdsdsdsd"+document_text);
for(var j=0; j < document_text.length ;j++)
{
text += document_text[j]['text'];
}
//file_names.push(convertStringToTextFile(text));
convertStringToTextFile(text,function(err,file_name){
if(err){
console.log(err);
loopCallBack(err);
}
else {
file_names.push(file_name);
loopCallBack();
}
})
},function(err){
if(err){
console.log(err);
next(err);
}
else {
var updateQuery = "select name from project where id in (?)";
console.log(updateQuery);
connection.query(updateQuery,[projectId], function (err, results) {
console.log("inside" + updateQuery);
connection.release();
if (err) {
console.log("error" + JSON.stringify(err));
debug(err);
next(err);
}
else {
var fileName_link = JSON.stringify(results[0].name);
console.log("projectname"+fileName_link);
convertTextFilesToZip(file_names,fileName_link, function (err, filename) {
if (err) {
console.log(err);
next(err);
}
else {
console.log("filename link" + filename);
res.json({
status: 0,
file_link: filename
});
}
});
}
});
}
});
}
});
}
});
}
}
convertStringToTextFile = function(text,cb){
var json_filename = 'tmp/file_'+uuid.v4().replace('-','')+'.txt';
fs.writeFile(json_filename, text , function (err) {
if (err) {
debug(err);
cb(err);
}
else{
cb(null,json_filename);
}
});
};
convertTextFilesToZip = function(textFiles,file_link,cb){
console.log("textfiles"+textFiles);
var filename = 'reports/'+JSON.parse(file_link)+'_extractedText.zip';
var output = fs.createWriteStream(filename);
output.on('close', function() {
console.log(zipArchive.pointer() + ' total bytes');
console.log('archiver has been finalized and the output file descriptor has closed.');
});
zipArchive.on('error', function(err) {
cb(err);
});
zipArchive.pipe(output);
zipArchive.bulk([
{ expand: true, src: textFiles }
]);
zipArchive.finalize();
cb(null,filename);
}
It works okay the first time and after that it throws this error.I have checked other posts in which res is returned twice but i couldn't find it.It says that can't set headers after they are sent.I think the problem is in the convertTextFilesToZip function but i cant seem to pinpoint the exact location which is generating the error.ANy help is appreciated.
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:350:11)
at ServerResponse.header (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:700:10)
at ServerResponse.send (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:154:12)
at fn (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:934:10)
at View.exports.renderFile [as engine] (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/jade/lib/index.js:374:12)
at View.render (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/view.js:93:8)
at EventEmitter.app.render (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/application.js:566:10)
at ServerResponse.res.render (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:938:7)
at /Users/zeeshandar/Desktop/Agreements_info/agreements_info/app.js:207:13
at Layer.handle_error (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/li b/router/layer.js:58:5)
Making my comment into an answer since it appears to have led to the solution.
The variable zipArchive is not initialized in convertTextFilesToZip() therefore you are reusing that variable from one function call to the next and that seems unlikely to be the right implementation.
Also, I would expect your method calls to zipArchive to be asynchronous and it doesn't look like your are coding for that since the callback is called before you have any sort of completion notification.

Node/Express function and callback are not breaking with return

I am creating a 'refresh data' function in Node and I cannot figure out where to place the callbacks and returns. The function continues to run. Below is a list of things the function should do. Could someone help out?
Check if a user has an api id in the local MongoDB
Call REST api with POST to receive token
Store token results in a MongoDB
Terminate function
./routes/index.js
router.post('/refresh', function(req, res) {
var refresh = require('../api/refresh');
refresh(req, function() { return console.log('Done'); });
});
../api/refresh.js
var callToken = require('./calltoken');
var User = require('../models/user'); // Mongoose Schema
module.exports = function(req, callback) {
User.findOne( {'username':req.body.username}, function(err, user) {
if(err) { console.log(err) }
if (user.api_id == 0) {
callToken.postToken(req.body.username, callback);
} else { // Do something else }
});
};
./calltoken.js
var request = require('request');
var Token = require('../models/token'); // Mongoose Schema
module.exports = {
postToken: function(user, callback) {
var send = {method:'POST', url:'address', formData:{name:user} };
request(send, function(err, res, body) {
if(err) { console.log(err) }
if (res.statusCode == 201) {
var newToken = new Token();
newToken.token = JSON.parse(body).access_token['token'];
newToken.save(function(err) {
if(err) { console.log(err) }
return callback();
});
}
});
}
};
I'm not an expert in Express but everywhere in you code in lines with if(err) { console.log(err) } you should stop execution (maybe of course not - up to you app) and return 400 or 500 to client. So it can be something like
if(err) {
console.log(err);
return callback(err); // NOTICE return here
}
On successful execution you should call return callback(null, result). Notice null as a first argument - it is according nodejs convention (error always goes as first argument).

how to run code sequentially in node js

Hi I have this code but when finish the result is not the espected because didn't run in the sequence that I wish
here is the code:
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
var req_games = [];
if (!err) {
for (var i in games) {
req_games.push(games[i]);
models.users.findOne({_id: games[i].w_id}, function (err, user) {
req_games[i].w_id = user.user;
console.log(req_games[i].w_id) //< -- 3
});
console.log('a ' + req_games[i].w_id) //<-- 2
}
user_data.games = req_games; // <-- 1
}
});
at the end of the task req_games didnt have any update because it's running in the sequence that I put in the comments in the code
This may help you using Q(promises)
obj.find = function(model, condition) { //make your find to return promise
var deferred = q.defer();
model.find(condition, function(err, results) {
if (err) {
logger.log(err);
deferred.reject(err);
} else {
deferred.resolve(results);
}
});
return deferred.promise;
}
ArraysOfId.forEach(function (id) {
var tempProm = mongoUtilsMethodObj.find(schemaObj.Asset, id).then(function (assetObj) {
---- your code
return q.resolve();
});
promArr.push(tempProm);//push all promise to array
});
q.all(promArr).then(function () {
// this will be called when all promise in array will we resolved
})
Here is a version using the async library to map your game values.
var async = require('async');
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
if(err) {
// or whatever your error response happens to be
return res.render('user.swig', {error: err});
}
async.map(games, function(game, nextGame) {
models.users.findOne({_id: game.w_id}, function (err, user) {
game.w_id = user.user;
nextGame(err, game);
});
}, function(err, req_games) {
user_data.games = req_games;
res.render('user.swig', {user: user_data});
});
});

How to add field to mongoose query result?

exports.getCityCascade = function (req, res) {
var result = {};
Province.find().exec(function (err, provinces) {
result.provinces = provinces;
var provinceCount = 0;
async.whilst(
function () {
return provinceCount < provinces.length
}
, function (callback) {
City.find({province: provinces[provinceCount].id}).exec(function (err, cities) {
if (err) {
callback(err);
} else {
result.provinces[provinceCount].cities =cities;
}
provinceCount++;
callback(null , result);
});
}, function (err, result) {
if (err) return res.jsonp({message: err.message});
return res.jsonp({
status: '200',
results: result});
}
)
})
}
When I add the cities field to provinces, It seems doesn't work. the response body doesn't contain the filed cities. How to fix it? Any advice would be very helpful.
The problem is just a conflict between variable names: you declared a var result outside Province.find(), but the async.whilst() also uses result as the second argument of its callback function. Just rename one of them and it should work.

Resources