Nodejs code giving error (err) - node.js

I'm using a nodejs code to generate a application package, but I want to check if a certain string is written in a text file. I only want to generate the application if the string is indeed in the text file.
I'm using this function to check that:
function checkValid(err, data) {
fs.readFile('http://domain.com/directory/data.txt', function (err, data) {
if (err) throw err;
if(data.indexOf('milk') < 0){
console.log(data)
}
});
}
//end of valid checker
And here I'm calling the function:
async.parallel(callItems, function(err, results) {
if(err) {
console.error("**** ERROR ****");
} else {
checkValid(err, data);
// Here I'm checking
createSourceDirectories(destDir, packageName);
copySourceDirectories(destDir, packageName);
removeBootstrapDirectories(destDir);
sendContentAsZip(destDir, res);
}
});
Please, you can check my whole code at: http://pastebin.com/2d7LtBgb
Everytime it returns an error, any idea? and preferably any (noob proof, I'm a very beginner) solutions.

Are you sure you can directly read a remote file with the "read" method?

Related

Return 404 code in proper way instead empty array

I have an quite simple application the idea is that someone has unique code which value are stored in one mongo collection in other we are keeping some data which we need to return if the key was found in first collection.
As probably you have noticed I'm using NodeJS with MongoDB and Mongoose, Express.
I have a problem with method bellow:
exports.getCompanyByKey = function(req, res) {
console.log(req.params.keyvalue);
var query = Company.where({keyValue : req.params.keyvalue});
query.findOne(function(err, company){
if(err){
res.send(err);
}else{
SampleData.findOne({}, function(err, sample_data){
if(err)
res.send(err);
res.json(sample_data);
});
}
});
};
The problem is that it will always return the data beause it's not throwing an error but empty array - so is there any other good and proper way as it should be don to throw 404 error without statement such as if(length<0) res.status(404).send('Error message).
I simply want to minimalize amount of if statements.
Maybe there is some other way to write implementation od error handling for mongoose which in general instead returning empty array will give us error code with message?
It's not exactly clear what you're asking, but if you want to make an error condition out of something that is not normally an error, then an if statement (or some other test like that) is required to test for that specific condition.
You could make your own function for querying that turns an empty response into an error and you could "hide" the if condition in that function if you want, but it's still an if condition that tests for your specific condition.
So, to return a 404 if the array is empty, you would just add an if statement (as you already appear to know):
exports.getCompanyByKey = function(req, res) {
console.log(req.params.keyvalue);
var query = Company.where({keyValue : req.params.keyvalue});
query.findOne(function(err, company){
if(err){
res.status(500).send(err);
} else {
SampleData.findOne({}, function(err, sample_data){
if(err) {
res.status(500).send(err);
} else {
if (sample_data.length) {
res.json(sample_data);
} else {
res.status(404).send("no data");
}
}
});
}
});
};
FYI, you also need to make sure you are properly setting a status code when there's an error and that you are never sending multiple responses to the same request (even when there's an error). I've also fixed several cases of those issues in your code.
This could likely be written cleaner and responses consolidated by using the promise interface to your database and send an error in one .catch().
For example, you could simplify your code by creating a utility function for .findOne() that detects and sends an error response automatically:
function findOne(res, db, q, cb) {
db.findOne(q, function(err, data) {
if (err) {
res.status(500).send(err);
cb(err);
} else if (!q.length) {
res.status(404).send("no data");
cb(new Error("no data"));
} else {
cb(null, data);
}
});
}
Then, your function could be simplified to this:
exports.getCompanyByKey = function(req, res) {
var query = Company.where({keyValue : req.params.keyvalue});
query.findOne(function(err, company){
if(err){
res.status(500).send(err);
} else {
findOne(res, SampleData, {}, function(err, sample_data) {
// any error response has already been sent
if (!err) {
res.json(sample_data);
}
});
}
});
};
Again, this would be better to use your Db's promise interface.

Show entire MongoDB contents in Node.js API

First off, don't worry, it's a tiny data set - I realise it wouldn't be wise to dump an entire production DB to a single screen via an API... I just need to get a JSON dump of entire (small) DB to return via an API endpoint in a Node.js application.
My application does successfully return single records with this code:
MongoClient.connect("mongodb://localhost:27017/search", function (err, db) {
if(err) throw err;
db.collection('results', function(err, collection) {
// search for match that "begins with" searchterm
collection.findOne({'string':new RegExp('^' + searchterm, 'i')}, function(err, items){
// get result
var result;
if (items == null || items.result == null){
result = "";
}
else {
result = items.result;
}
// return result
res.send(result);
});
});
});
So I know Node is talking to Mongo successfully, but how can I tweak this query/code to basically return what you get when you execute the following on the MongoDB command line:
$ db.results.find()
This is snippet.
model.find({}).exec(function (err, result) {
if (err) {console.error(err); return;}
else return result;
});
First use your predefined model and call find. the logic is to place a empty object {} essentially rendering . select all from this model.
Make sense?
Exactly as you've described it.
collection.find({}).exec((err, result) => {
if (err) {
console.log(err);
return;
}
if (result.length > 0) {
// We check that the length is > 0 because using .find() will always
// return an array, even an empty one. So just checking if it exists
// will yield a false positive
res.send(result);
// Could also just use `return result;`
});
Thanks guys, I appreciate your answers pointing me in the right direction, in terms of using {} as the query. Here is the code that eventually worked for me:
db.collection('results', function(err, collection) {
collection.find({}).toArray(function(err, docs) {
res.send(docs);
});
});
The crucial element being the toArray(...) part.

node.js passing value to a variable in async mode

My problem is the following:
I have a nice folder crawler function, which grabs the paths' of the files. I'm (I would like to) use these files for testing purposes.
1.) Grabbing the files
2.) Do some testing
3.) Job Done
This is the code where I call it:
walk(csvRoot, function(err, results){
if (err) throw err;
for (var i = 0; i < results.length; i++) {
return results[i] // - not working
}
});
My main issue is, that I really would like to pass the results to a variable, which will contain these paths as an array, but so far no luck.
The variable returns as undefined, that's what I'm trying to resolve currently.
Could you please advise how to do so?
Why do you use return within the for loop? What do you expect to return there? In any case, if you are expecting to have the results available outside of the scope of the walk function, it will not work. I pressume that you need something like that:
function getFiles (csvRoot, callback) {
walk(csvRoot, function (err, results) {
if (err) {
return callback(err);
}
return callback(null, results);
});
}
getFiles(csvRoot, functions (err, files) {
// #todo: check for error
console.log(files);
});

Is Error Trapping Data Returned by an Error-First Callback a Good Practice?

dataObject.query(err, data){
if(!data){return;}
else if(err){console.log("There is an error");}
else{console.log(JSON.stringify(data));}
}
The author of Getting MEAN with Mongo, Express, Angular, and Node features a code segment in a API controller that is similar to the code above. Is the error trapping conducted in the first if statement for the "data" object necessary, considering the fact that the callback function already features an err object?
If (!data) == true then it means there is no data received from the query. This is not an error, but just a query with 0 results (and as you can see no error is logged to console).
However the correct way to check is to flip the order between the first 2 conditions:
dataObject.query(err, data){
if(err) { console.log("There is an error"); } // If there's an error from the query then log it.
else if(!data) { console.log("There's no data"); } // If the result is empty (no data) then log that there's no data. (It is better to return a false value or some other indication that there was no result).
else { console.log(JSON.stringify(data)); } // Finally, if there are results and no errors, log them as a string (pay attention that I've also fixed that function).
}
Normally you check error first:
function (err, data) {
if (err) {
return callback(err);
}
}
Then you can check data, if it still can be missing. You can just short-circuit your function or call callback with a new error:
function (err, data) {
if (err) {
return callback(err);
}
if (!data) {
return callback(new Error('No data.')); // or callback(null, data) or something like that
}
}
Doing that in a different order makes no sense as in case of error data would be most likely missing.

Optimal design pattern - functions which process multiple files

Goal is to create distinct functions which separate out the work of loading multiple (xml) files and parsing them. I could do this all in one function, but the nested callbacks begin to get ugly. In other words, I don't want to do this:
// Explore directory
fs.readdir(path, function (err, files) {
if(err) throw err;
// touch each file
files.forEach(function(file) {
fs.readFile(path+file, function(err, data) {
if (err) throw err;
someAsyncFunction ( function (someAsyncFunctionResult) {
// Do some work, then call another async function...
nestedAsynchFunction ( function (nestedAsyncFunctionResult) {
// Do Final Work here, X levels deep. Ouch!
});
});
});
});
});
Instead, I want one function which reads my files and puts each file's XML payload into an array of objects which is returned to the caller (each object represents the name of the file and the XML in the file). Here's the function that might load up reports into an array:
function loadReports (callback) {
var path = "./downloaded-reports/";
var reports = [];
// There are TWO files in this path....
fs.readdir(path, function (err, files) {
if(err) throw err;
files.forEach(function(file) {
fs.readFile(path+file, function(err, data) {
if (err) throw err;
reports.push({ report: file, XML: data.toString()});
//gets called twice, which makes for strangeness in the calling function
callback(null, reports);
});
});
// callback won't work here, returns NULL reports b/c they haven't been processed yet
//callback(null, reports);
});
}
...and here's the function which will call the one above:
function parseReports() {
loadReports( function(err, data) {
console.log ("loadReports callback");
var reportXML = new jsxml.XML(data[0].XML);
var datasources = reportXML.child('datasources').child('datasource').child('connection').attribute("dbname").toString();
console.log(JSON.stringify(datasources,null, 2));
// More async about to be done below
} );
}
As you can see in the loadReports() comments, I can't get the callback to work right. It either calls back BEFORE the array is has been populated at all, or it calls back twice - once for each fs.readFile operation.
SO...what is the best way to deal with this sort of situation? In brief - What's the best design pattern for a function which processes multiple things asynchronously, so that it ONLY calls back when all "things" have been completely processed? The simpler the better. Do I need to use some sort of queuing module like Q or node-queue?
Thanks much!
Edit: Something like this works inside the deepest loop in terms of not hitting the callback twice, but it seems like a kludge:
fs.readdir(path, function (err, files) {
if(err) throw err;
files.forEach(function(file) {
fs.readFile(path+file, function(err, data) {
if (err) throw err;
reports.push({ report: file, XML: data.toString()});
// WORKS, but seems hacky.
if (reports.length = files.length) callback(null, reports);
});
});
});

Resources