I want to read line by line file and compare with value in a object that where passed to my function. Unfortunately I get information that object is undefined but when I checked it showed me correct data. This is code
module.exports = function savefile(pathname, changesvalue){
var counter = 0;
var i = 0;
var message = [];
var test = changesvalue[i].seekrange; //here I have correct information
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(pathname)
});
lineReader.on('line', function (line) {
if(counter == parseInt(changesvalue[i].seekrange)){ //here it showed that value is undefind
var textadd = changesvalue[i].seektext.match(/([a-zA-Z-/]+)/g);
message.push(' ' + textadd[0] + ' ' + changesvalue[i].seekvalue + textadd[1]);
i++;
}
else{
console.log(line);
}
counter++;
});
lineReader.on('end', function () {
fs.writeFile('file_to_save_to', message, function(err) {
if (err) {
return console.log(err);
}
});
}
};
I don't now exactly why I get undefined? And how to processes this file in efficient way to read file, change some line and write to file?
Thank you for your help
Related
I'm just learning not to judge strictly. I try to do Rest Client. And I want to do a data search by rows.
At the moment I just want to try to find the given data in the array. And if one of the lines is the same, the message OK will be displayed, and in the others No. But I have all messages displays No. How to fix it?
var data = querystring.stringify({
Name: "CEO"
})
var req = http.request(options, function(res) {
console.log("status: " + res.statusCode);
var content = ''
res.on('data', function(chunk) {
content += chunk
for (var i = 0; i < content.length; i++) {
if (content[i] === data) {
console.log('Ок')
} else {
console.log('No')
}
}
});
}).on('error', function(e) {
console.log("error: " + e.message);
});
req.write(data)
req.end()
-
console.log(`body: ${(chunk)}`):
Answer:
body: {"rowsCount":75,"rows":[..., {"Id":75,"Name":"CEO"}]}
There are some programming / logical problem with your code that prevent you from getting the desired result.
One of the most important parts (sometimes the trickiest one) of programming is to know the types of data you are dealing with then handle them properly.
As in the problem you are resolving, the data returned from the API is in JSON format, and can be treated as object in javascript. You don't have to do a string concat to append them to content variable. By appending chunk to the content variable, you turn the whole set of data return to you to a string, doing a for loop on a string have a very different result compared with on an array.
The second issue is if you look into the data structure that returns to you through the api, the list of records you want to search on is under the rows attribute, therefore, you should loop through the chunk.rows only.
A suggesting fix for your code will be as follows:
var searchQuery = 'SEO';
var req = http.request(options, function(res) {
res.on('data', function(chunk) {
for (var i = 1; i <= chunk.rows.length; i++) {
if (chunk.rows[i].Name === searchQuery) {
console.log('Ок')
} else {
console.log('No')
}
}
});
}).on('error', function(e) {
console.log("error: " + e.message);
});
req.write(data)
req.end()
Your for-loop will skip the first element of the data you get back
You aren't accessing the desired search property correctly.
Your query is a string for which you are testing equality against an object.
You need to access the rows property of your incoming data and then perform your query:
Attempt one:
const rowsToSearch = content.rows; // #2
for (var i = 0; i < rowsToSearch.length; i++) { // #1
if (rowsToSearch[i].Name === 'CEO') { // #3
console.log('Ок')
} else {
console.log('No')
}
}
Attempt two, using lodash:
const query = { Name: 'CEO' };
const rowsToSearch = chunk.rows;
for (var i = 0; i < rowsToSearch.length; i++) {
if (_.isEqual(rowsToSearch[i], query)) {
console.log('Ок')
} else {
console.log('No')
}
}
Attempt 3, using ES6 iteration and lodash:
const query = { Name: 'CEO' };
const rowsToSearch = chunk.rows;
const result = rowsToSearch.find(row => _.isEqual(row, query));
result ? console.log('OK') : console.log('No');
var std;
......
...... // here I fill std with some data
......
I'm trying to access the 'std' array while handling this route:
app.post('/saveABS',function(req,res){
var fileName = "./public/"+f;
fs.writeFile(fileName, JSON.stringify(std, null, 4), function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved !");
console.log(a);
for(var i = 0; i < std.length; i++)
{
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'admin' ,
database : 'pfe'
});
console.log('before hr_cours = ' + std[i].hr_cours); // <========= WORKS
Here it displays the value of std[i].hr_cours correctly.
if(std[i].hr_cours != a[i].hr_cours)
{
connection.connect(function(error){
console.log('after hr_cours = ' + std[i].hr_cours); // <============ undefined
Here it displays undefined.
if(error)
{
console.log('Unable to connect to database.');
}
else
{
console.log("i= " + i);
console.log("I'm in : hr_cours = " + std[i].hr_cours);
connection.query("INSERT INTO assiste VALUES (CURDATE(),(SELECT id_etud FROM Etudiant WHERE nom_etud = ?),(SELECT s.id_seanceFROM Seance s, aura_lieu a, jour j, fait_objet fWHERE s.id_seance = a.id_seanceAND CURTIME() BETWEEN a.heure_debut AND a.heure_fin AND a.id_jour = j.id_jour AND j.dat = CURDATE() AND f.id_seance = s.id_seance AND f.id_ens = ?), ?)", [std[i].nom_etud, idEns, std[i].hr_cours], function(er1, res1){
if(er1)
{
console.log('Query error: ');
}
else
{
console.log('success');
}
});
}
});
}
}
res.end("all");
}
});
});
I noticed that the issue is triggered once the execution flow enters the connection.connect block and that it's a scope issue; I searched everywhere for the answer but couldn't find a solution to my specific problem.
How can I make this work?
The execution of connection.connect is delayed and therefore when it fires i is not the same value as when a reference to i was passed in to it by the for loop. So, to lock in the value of i in that particular loop execution, wrap the connection.connect method and callback in an IIFE and pass i as it's parameter:
~function(i) {
connection.connect(function(error){
console.log('after hr_cours = ' + std[i].hr_cours);
// other stuff
})
}(i)
A more detailed explanation of IIFE's and scope closure in my answer here: Odd javascript code execution order
And a JSFiddle playground to explore the technique: IIFE Scope Closure With Pre-Existing Parameters.
Here's your problem:
app.post('/saveABS', function(req, res) {
// ...
for (var i = 0; i < std.length; i++) {
// ...
// This is SYNC. Here i = 0,1,2...
connection.connect(function(error) {
// This is A-SYNC.
// Here i = std.length + 1
// always!
// No matter even if it syntactically looks like i should be 1,2,3 according to the loop
// but all of this is executed way after the loop has long been completed
// ...
// Here it displays undefined.
console.log('after hr_cours = ' + std[i].hr_cours); // <============ undefined
A solution: Have a self executing anonymous function (function(){})() inside the loop and pass it the arguments (i) so that they will stay the same
for (var i = 0; i < std.length; i++) (function(i){
connection.connect(function(error) {
// ...
// Here, since i is an argument passed to outer function
// i will be i,2,3...
})(i);
Another solution: forEach loop, which already has a callback function
std.forEach(function(currentValue, i, std){
connection.connect(function(error) {
// ...
// Same here, since i is an argument passed to outer function
// i will be i,2,3...
// Also currentValue = std[i] so you can use that
});
I am currently trying to iterate through an array of JSON elements, parse and add the data I need into a specially formatted string, and once conditions are met, initiate the uploading of this data.
The problem that I am running into, however, is my variable 'deviceOutString' is being returned as undefined, leaving me with a string of 'undefined' written as many time as there are JSON elements in the array. I know that the return from the 'checkDuplicates' function is correct because before returning the value, the logs show that the value is correct.
I have attached my code below, please let me know if you have any ideas.
Thanks!
Old Code (updated below)
var i=0;
var parsedJson = JSON.parse(storedData) ;
var storedDataSize = parsedJson.length;
console.log('Stored Data Size: '+storedDataSize);
var async = require('async');
async.each(parsedJson, function( subElemJson, callback1) {
async.series([
function(callback){
console.log('dstring: ' + deviceOutString);
console.log('i : ' + i);
var subElemJsonPretty = JSON.stringify(subElemJson,null,0) ;
var date = subElemJson['date'];
deviceOutString += checkDuplicates(subElemJson, deviceOutString);
console.log('theLoop*DString: ' + deviceOutString);
callback(null, 'one');
},
function(callback){
if((i == storedDataSize - 1 || count == 225) && storedDataSize > 0) {
writeDCC(deviceOutString);
count = 0;
makeList();
}
i++;
callback(null, 'two');
setTimeout(function () { callback1(); }, 500);
}
]);
}); }
Updated New Code
function theLoop(storedData) {
var deviceOutString = '<list>';
var temp;
try {
var i=0;
var parsedJson = JSON.parse(storedData) ;
var storedDataSize = parsedJson.length;
console.log('Stored Data Size: '+storedDataSize);
var async = require('async');
var delayed = require('delayed');
async.each(parsedJson, function( subElemJson, callback1) {
async.series([
function(callback){
var subElemJsonPretty = JSON.stringify(subElemJson,null,0) ;
var date = subElemJson.date;
console.log('THIS IS THE DATE: '+date);
temp = checkDuplicates(subElemJson, deviceOutString);
console.log('This is the temp: ' + temp);
callback(null, temp);
}
], function(results){
console.log('*****Results are In*****: ' + results);
deviceOutString =+ temp;
if((i == storedDataSize - 1 || count == 225) && storedDataSize > 0) {
writeDCC(deviceOutString);
count = 0;
deviceOutString = '<list>';
}
i++;
callback1(results);
});
},
function(err){
if( err ) {
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
} catch (error) {
console.info('Exception parsing ' + '\n\n' + error);
return;
}
}
So a few things
1: var date = subElemJson['date']; accessing object properties via array syntax is a bad practice. Nit picky but hey :P try var data = subElemJson.date; instead.
2: deviceOutString isn't defined anywhere in the code you provided.
3: Both async.series and async.each are going to want a callback function for when each is finished. that's the whole point of calling callback(null, 'one'); -- that you pass a value to the "results" array in the final async.series callback. You are calling setTimeout(function() { callback1(); }, 500); in the wrong place (also arbitrarily putting it behind a timeout?).
The proper async.series formatting is thus:
async.series([
function(callback) {
// do stuff
callback(null, someValue);
},
function(callback) {
// do other stuff
callback(null, someOtherValue);
}
], function(results) {
// all the stuffs are done
console.log(results); <-- results is an array containing "someValue" and "someOtherValue" from the iterations above
callback1(results);
});
Also, async.each is in the same boat -- it expects you to pass a "every thing I'm looping through has completed now!" function at the end.
Async docs on .each() (scroll down for docs on .series()): https://github.com/caolan/async#each
I've been looking around for a few days not and really I feel like I'm missing a part of the concept here... I'm fairly new with node.js, and I'm trying to call a method from a different module in my main class per-say...
Here is the code..
inputReader.js
(function() {
var dir = './views/'; // Declare the directory to be scanned
var data = {} // Create array object for storage
fs.readdir(dir, function(err, files) {
if (err) {
throw err;
}
var c = 0; // Declare a var c = 0; initial condition of a for loop
files.forEach(function(file) {
c++; // Increment a counter in the for-loop condition
fs.readFile(dir+file, 'utf-8', function(err, string) {
if (err) {
throw err;
}
if ( 0 === -3) {
data[file] = string; // Throws into data object string of contents within the file being read
console.log(data); // We only need this to test using console (the contents being stored)
}
});
});
});
module.exports.getData = function() {
return data();
}
}());
And here is how I'm trying to call it in app.js
var inputReader = require('./inputReader').inputReader;
app.get('/', function(req, res){
res.send(inputReader.getData());
});
app.listen(3000);
console.log('Listening on port 3000');
My prediction for if I did this correctly, my localhost page would display the contents of the files within the folder I designated the app to read; ./views/.. but clearly, I am doing something very wrong as the error I'm getting is:
TypeError: Cannot call method 'getData' of undefined at c:\Users\Brian\documents\visualizer\app.js:21:24 at callbacks (c:\Users\Brian\documents\visualizer\node_modules\express\lib\router\index.js:164:37) at param (c:\Users\Brian\documents\visualizer\node_modules\express\lib\router\index.js:138:11) at pass (c:\Users\Brian\documents\visualizer\node_modules\express\lib\router\index.js:145:5) at Router._dispatch (c:\Users\Brian\documents\visualizer\node_modules\express\lib\router\index.js:173:5) at Object.router (c:\Users\Brian\documents\visualizer\node_modules\express\lib\router\index.js:33:10) at next (c:\Users\Brian\documents\visualizer\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.expressInit [as handle] (c:\Users\Brian\documents\visualizer\node_modules\express\lib\middleware.js:30:5) at next (c:\Users\Brian\documents\visualizer\node_modules\express\node_modules\connect\lib\proto.js:193:15) at Object.query [as handle] (c:\Users\Brian\documents\visualizer\node_modules\express\node_modules\connect\lib\middleware\query.js:44:5)
If someone may point me to the right direction or explain to me what I am doing wrong, that would be appreciated
Thank you! (And sorry for the long read..)
Several different way to write it out:
// inputReader.js
module.exports.getData = function() {
return data();
}
// app.js
var inputReader = require('./inputReader'); // inputReader contains getData
inputReader.getData();
or
// inputReader.js
module.exports.getData = function() {
return data();
}
// app.js
var inputReader = require('./inputReader').getData; // inputReader is now getData
inputReader();
or
// inputReader.js
var theModule = {
getData : function() {
return data();
}
}
module.exports = theModule;
// app.js
var inputReader = require('./inputReader');
inputReader.getData();
or
// inputReader.js
var theModule = function() { /* constructor */ };
theModule.prototype.getData = function() {
return data();
};
module.exports = theModule;
// app.js
var inputReader = require('./inputReader');
new inputReader().getData();
NEW POST:
Here is the sample of the working async code without a db.
The problem is, if i replace the vars (data1_nodb,...) with the db.collection.find();
function, all needed db vars received at the end and the for() loop ends not
correct. I hope that explains my problem a bit better. OA
var calc = new Array();
function mach1(callback){
error_buy = 0;
// some vars
for(var x_c99 = 0; x_c99 < array_temp_check0.length;x_c99++){
// some vars
calc[x_c99] = new Array();
calc[x_c99][0]= new Array();
calc[x_c99][0][0] = "dummy1";
calc[x_c99][0][1] = "dummy2";
calc[x_c99][0][2] = "dummy3";
calc[x_c99][0][3] = "dummy4";
calc[x_c99][0][4] = "dummy5";
function start_query(callback) {
data1_nodb = "data1";
data2_nodb = "data2";
data3_nodb = "data3";
data4_nodb = "data4";
calc[x_c99][0][0] = data1_nodb;
calc[x_c99][0][1] = data2_nodb;
calc[x_c99][0][2] = data3_nodb;
callback(data1_nodb,data2_nodb,etc..);
}
start_query(function() {
console.log("start_query OK!");
function start_query2(callback) {
data4_nodb = "data5";
data5_nodb = "data6";
data6_nodb = "data7";
calc[x_c99][0][3] = data4_nodb;
calc[x_c99][0][4] = data5_nodb;
callback(data5_nodb,data6_nodb,etc..);
}
start_query2(function() {
console.log("start_query2 OK!");
function start_query3(callback) {
for(...){
// do something
}
callback(vars...);
}
start_query3(function() {
console.log("start_query3 OK!");
});
});
});
}
callback(calc);
};
function mach2(callback){
mach1(function() {
console.log("mach1 OK!");
for(...){
// do something
}
});
callback(calc,error_buy);
};
mach2(function() {
console.log("mach2 OK 2!");
});
OLD POST:
i try to read data from the mongodb and send them back with a callback to the next
function, that needs the infos from the db to proceed.
Without the mongodb read functions it works perfect but now i dont know how
i can send the db vars out of the two inner functions to the first callback function.
Hope someone can help me...
Thanks
var error = 0; var var1 = "yessir";
function start_query(callback) {
var db_name = "db1";
db[db_name].find({name:var1},{data1:1, data2:1, data3:1, data4:1}, function(err, data_catch,callback) {
if( err || !data_catch ) {
console.log("Problem finding data_catch:" + err);
} else {
data_catch.forEach( function(data_catch_finder,callback) {
data1_db = data_catch_finder.data1;
data2_db = data_catch_finder.data2;
data3_db = data_catch_finder.data3;
data4_db = data_catch_finder.data4;
if(data1_db == "" || data2_db == "" || data3_db == "" || data4_db == ""){error = 1; console.log("Error: data_catch_finder");}
callback(data1_db, data2_db, data3_db, data4_db, error);
});
}
});
callback(data1, data2, data3, data4, error);
}
//########################################################################
start_query(function() {
function start_query2(callback) {
console.log("DATA1 from callback:" + data1_db);
console.log("DATA2 from callback:" + data2_db);
console.log("DATA3 from callback:" + data3_db);
console.log("DATA4 from callback:" + data4_db);
var var_no_db = "testing";
//do something else and callback
callback(var_no_db);
}
start_query2(function() {
console.log("Var from callback start_query2:" + var_no_db);
console.log("The end");
});
});
your callback signature are issuing callback as a parameter.
As far as I can understand your code, you need to keep reference of the first callback, the one you receive here: function start_query(callback).
In every callback function you made the mistake to bind the variable name callback to the parameter from the mongo driver (a simple undefined i think).
You can fix it removing every reference of callback from the signature of your inner functions.
a simple example:
function async (cb) {
// params: Error, data
cb(null, 'moo');
}
function foo(callback) {
async(function(err, data, callback){
console.log(callback); // undefined
});
console.log(callback); // Moo
}
foo('Moo');
Take a look at Eloquent Javascript to better understand the JS context switching;
edit
The only way to wait the results of an async function is recall the first callback inside the last nested callback.
function ugly_nested (callback) {
dbquery('...', function(err, data_01) {
if (!! err) return callback(err);
dbquery('...', function(err, data_02) {
if (!! err) return callback(err);
dbquery('...', function(err, data_03) {
if (!! err) return callback(err);
callback(null, data_01, data_02, data_03);
});
});
});
}
ugly_nested(function(err, data01, data02, data03) {
if (!! err) throw err;
manage_data(data01, data02, data03);
});
The FOR loop is synchronous, but, the database calls are asynchronous, so, the for loop will end before the database returns his results. If you really need that for loop you can try out one of the nice flow control libraries out there