I have this Node.js method for GET queries
app.get('/:tableName', function(req, res) {
var schema = require('./schema/' + req.param('tableName'));
var q = unescape(Object.keys(req.query)[0]);
console.log('query:' + q);
schema.find(q, function(err, result) {
if (err) {
console.log(err);
res.status(500).json({status: 'failure'});
}
if (result) {
res.json(result);
} else {
res.json({status: 'not found'});
}
});
});
The strage, that if I call it i.e. whit this input .. (it is exactly the value of var q)
{
"remoteID" : "80E75ED5-B696-446E-9AA7-9B170350D7E6"
}
.. I get back 3 items but non of them match the condition, basically it returns all the items in table.
[{"lastName":"K","remoteID":"D5DC51C1-C415-4073-A647-1D41BB47D03E","password":"p","firstName":"J","email":"xxx","airline":"73C02335-C019-419E-BCC7-C87537F38492","userName":"J","_id":"5353b639889a61000038848c","__v":0},
{"lastName":"asd","remoteID":"C471495C-C218-4440-BA81-7BD37CBB5605","password":"wn831","firstName":"asd","email":"asd#asd.hu","airline":"73C02335-C019-419E-BCC7-C87537F38492","userName":"ASA","_id":"5353b639889a610000388491","__v":0},
{"remoteID":"5A0D51DE-DCD0-4E3E-9D97-7CAD066DB68A","userName":"R","password":"R","_id":"5353b639889a610000388492","__v":0}]
One important line was missing:
var jq = JSON.parse(q);
schema.find(jq, function(err, result) {
find() method requires not string but JSON object.
Related
I am stuck in nodejs during calling of zendesk api.
As i called zendesk.tickets.incremental Api, it provides me ticketId and that used in another function for getting any change from previous by calling zendesk.tickets.exportAudit.
I also get response too but during fetching the data another ticketId called so previously flag an error in response "error: item not found " and than fetch the data for new ticketId and so on.
What I need, I need it block the process until data of first Id completely .
This is my code.
//Calling ticketIncremental Details ticketId (likes 1, 2 etc)
app.get('/', function (req, res) {
zendesk.tickets.incremental(0, function(err, statusList, body, responseList, resultList) {
if (err) {
console.log(err);
return;
}
var ticketIncreDetails = (JSON.stringify(body));
res.end(ticketIncreDetails);
for (var i=0; i< body.length; i++ ) {
ticketValues(body[i].id) //within this function another API of zendek calling for exportAudit
}
});
//This is for exportAudit
function ticketValues(ticketId) {
zendesk.tickets.exportAudit(ticketId, function(err,statusList, body, responseList, resultList) {
if(err) {
console.log(err);
return;
}
console.log("ticketExportAudit: " + JSON.stringify(body)) });
As #qxz say, it's better to check out if there is sync package or not, or you need to handle this focusing on callback because zendesk.tickets.exportAudit need time to complete its work, but for loop wouldn't act like that, the code below handle this problem with callback, you could have a look.
//Calling ticketIncremental Details ticketId (likes 1, 2 etc)
app.get('/', function (req, res) {
zendesk.tickets.incremental(0, function(err, statusList, body, responseList, resultList) {
if (err) {
console.log(err);
return;
}
var ticketIncreDetails = (JSON.stringify(body));
res.end(ticketIncreDetails);
ticketValues(body,body.length,0);
//ticketValues(body,body.length,0,function(){..if you wanna do something after..});
});
});
//This is for exportAudit
function ticketValues(ticket,length,index,callback) {
zendesk.tickets.exportAudit(ticke[index].id, function(err,statusList, body, responseList, resultList) {
if(index<length){
if(err) {
console.log(err);
return;
}else{
console.log("ticketExportAudit: " + JSON.stringify(body));
index++;
ticketValues(ticket,length,index,callback);
}
}else{
if(callback)
callback();
}
});
}
I posted a question before and realized my problem actually was async functions. I managed to work out most of it, but I got one little problem left. Using async I used waterfall to create an order for the some queries...
exports.getMenu = function(id_restaurant, callback){
async.waterfall([
async.apply(firstQuery, id_restaurant),
secondQuery,
thirdQuery,
fourthQuery,
formMenu
], function(err, result){
if(err){
console.log(err);
}
callback(result);
});
};
Everything works until fourthQuery, where I have to loop to get all dishes of a menu.
function fourthQuery(array_totalP, array_nombresSecc, array_secciones, callback){
var size = array_nombresSecc.length;
var array_secciones = array_secciones;
var array_nombresSecc = array_nombresSecc;
var dishes = [];
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
callback(true);
return;
}
for (var i = 0; i < size; i++) {
connection.query("SELECT name, price FROM menu_product WHERE id_seccion = ? AND active = 1", [array_secciones[i]],
function(err, results2) {
if(err) {
console.log(err);
callback(true);
return;
}
console.log("Result query 4 " + JSON.stringify(results2));
dishes[i] = results2;
console.log("VALOR PLATILLOS EN i : " + JSON.stringify(dishes[i]));
// this prints the result but only if it has a value over 2
});
};
}); // pool
console.log("I'm sending " + dishes); // this logs an empty array
callback(null, dishes, array_nombresSecc);
};
So what i can see that happens from printing the value of 'i' each loop is that it always has the value of 2. Because that's 'size' value. Also, even though it's saving results of index '2' I believe the callback is being done even before the for loop is done, because my fifth function is recieving an empty array.
How can i make my code wait to callback until my for loop is done?
NOTE: Sorry, part of my code is in spanish, tried to translate the important parts of it.
There are a few ways to handle this, one is to look into promise architecture. Promise.all will let you supply one callback to handle the values from each child promise.
To use what you've already got, however, I'd push the values into your dishes array, rather than assigning them specifically to i indexes, then check the size of that array at the end of each connection. When the array length matches the size, fire the callback. (as seen below)
If you need a way to tie each result to that specific i value, I'd recommend pushing them as an object
dishes.push({'index': i, 'dish': results2})
Afterward, if you need the array of just dishes, you can sort the array by that index value and run a map function.
dishes.sort(function(a,b){ return a.index - b.index; })
dishes = dishes.map(function(a){ return a.dish })
Here's the code adjusted:
function fourthQuery(array_totalP, array_nombresSecc, array_secciones, callback) {
var size = array_nombresSecc.length;
var array_secciones = array_secciones;
var array_nombresSecc = array_nombresSecc;
var dishes = [];
pool.getConnection(function(err, connection) {
if (err) {
console.log(err);
callback(true);
return;
}
for (var i = 0; i < size; i++) {
connection.query("SELECT name, price FROM menu_product WHERE id_seccion = ? AND active = 1", [array_secciones[i]],
function(err, results2) {
if (err) {
console.log(err);
callback(true);
return;
}
console.log("Result query 4 " + JSON.stringify(results2));
dishes.push(results2)
if(dishes.length == size){
console.log("I'm sending " + dishes);
callback(null, dishes, array_nombresSecc)
}
console.log("VALOR PLATILLOS EN i : " + JSON.stringify(dishes[i]));
// this prints the result but only if it has a value over 2
});
};
}); // pool
;
};
Since you're already using the async, I would suggest replacing the for() loop in fourthQuery with async.each().
The updated fourthQuery would look like this:
function fourthQuery(array_totalP, array_nombresSecc, array_secciones, callback){
var size = array_nombresSecc.length;
var array_secciones = array_secciones;
var array_nombresSecc = array_nombresSecc;
var dishes = [];
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
callback(true);
return;
}
async.each(array_secciones,
function(item, itemCallback) {
// Function fun for each item in array_secciones
connection.query("SELECT name, price FROM menu_product WHERE id_seccion = ? AND active = 1", [item],
function(err, results2) {
if(err) {
console.log(err);
return itemCallback(true);
}
console.log("Result query 4 " + JSON.stringify(results2));
dishes.push(results2);
console.log("VALOR PLATILLOS EN i : " + JSON.stringify(dishes[dishes.length-1]));
// this prints the result but only if it has a value over 2
return itemCallback();
});
},
function(err) {
// Function run after all items in array are processed or an error occurs
console.log("I'm sending " + dishes); // this logs an empty array
callback(null, dishes, array_nombresSecc);
});
}); // pool
};
Alternatively, you can use async.map(), which handles gathering the results in the final callback so doesn't rely on the dishes variable.
I'm trying to use async.each function to get an array with my results from two queries. After that, I need to render this results in a web page.
The async.each function calcule the variable results properly, but, I am not be able to export this variable outside the function and render it and I don't understand why.
Here I attached the code, where I tested it. I realized that when I call "callback1" the function(error) is not working and I don't get the variable list in the console (so I won't be able to render it later on). Please I would be grateful if someone could help me with that. Thanks a lot.
var list = [];
async.each(data,
function(elem, callback1){
var classgene = '';
var custom_gene = {};
custom_gene = {Name_Gene: elem['Name_Gene']};
if (elem['Type_Gene'] == "reference") {
async.waterfall([
function(callback2){
var id = elem['Id_Genes'];
geneModel.getGenesRefClass(id, function(error, data2){
classgene = data2[0]['Class_Name'];
custom_gene['classgene'] = classgene;
callback2(custom_gene);
});
},
], function(custom_gene, err){
list.push(custom_gene);
console.log(list);
callback1();
});
}
}, function(err){
// if any of the saves produced an error, err would equal that error
if(err){
console.log(list);
}else{
console.log(list);
}
});
Your code has a few problems:
It's not calling callback2() properly. It should be callback2(null, custom_gene) (the first argument is reserved for errors, or null if there aren't any). Preferably, you should also check for error being returned by geneModel.getGenesRefClass();
The previous issue also means that you need to swap the argument of function(custom_gene, err) (it should become function(err, custom_gene));
When elem['Type_Gene'] does not equal "reference", you should still call callback1(), otherwise async.each() doesn't know that the code is done;
So the code would become something like this:
var list = [];
async.each(data, function(elem, callback1) {
var classgene = '';
var custom_gene = { Name_Gene : elem['Name_Gene'] };
if (elem['Type_Gene'] == "reference") {
async.waterfall([
function(callback2) {
var id = elem['Id_Genes'];
geneModel.getGenesRefClass(id, function(error, data2){
if (error) return callback2(error);
classgene = data2[0]['Class_Name'];
custom_gene['classgene'] = classgene;
callback2(null, custom_gene);
});
},
], function(err, custom_gene) {
// If you want to propagate errors, uncomment the following:
// if (err) return callback1(err);
list.push(custom_gene);
console.log(list);
callback1();
});
} else {
callback1();
}
}, function(err){
// if any of the saves produced an error, err would equal that error
if (err) {
console.log('An error occurred!', err);
}
console.log(list);
});
I am trying to check to see if a document is already in the database before posting. I am posting via a jQuery.post() method to my endpoint which is api/songs.
What I want to check is to see if the song is already in the database. I can check that by querying the songId parameter that I am pushing to the database. If the song is already in the database I want to increment a number by 1.
What I have been trying to do is use mongo's findOne(), but I can't get it to work in the POST. My post route looks like this:
router.post('/api/songs', function(req, res){
if(Song.findOne({songId: req.body.songId}).length > -1){
console.log('already in there fam')
} else{
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
};
console.log(song);
return res.json({message: "SongCreated"})
})
My problem is that I can't figure out what the findOne is returning. I want it to return a boolean so i've tried count() and length() but can't get it to return true. The req posts to the DB no matter what.
Any ideas?
All i/o operations in node.js are asynchronous. Your Song.findOne operation is asynchronous as well. You should wait for it to complete via callback functionality and then check the result of it.
Mongoose findOne method returns a promise. You can read more info about it here.
Example of promise execution:
var query = Song.findOne({songId: req.body.songId})
query.exec(function(err, song) {
})
Try the following code:
router.post('/api/songs', function(req, res){
Song.findOne({songId: req.body.songId}, function(err, song){
if (err) {
return console.log("Error: " + err)
}
if(song){
return console.log('already in there fam')
}
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
console.log(song);
return res.json({message: "SongCreated"})
})
})
I tried to scrap for thousands of pages. So I used async.timesSeries and async.waterfall. Each of functions work synchronously very well but they don't work together. What can I do?
The logic is simple.
Because I want to scrape pages are "http://udb.kr/local/category/390101?page="1~1167, async.timesSeries loop 1 to 1167
async.waterfall scraps components of pages
but messages that console shows me looks like this
info.NM values // just for explain, It shows me each attires of obj because I insert console.log(info.NM) for verifying.
info.NM values
info.NM values
info.NM values and randomly ----- page number -----
...
['done',
'done',
'done',
'done',
'done',
...
'done']
info.NM values again
.../Users/Snark/Dev/job_apply/cheerio_job_app_list.js:29
if (tObj[m+1].children != 0) {info.nAddr = tObj[m+1].firstChild.data}else{info.nAddr = null};
^
TypeError: Cannot read property 'children' of undefined
at /Users/Snark/Dev/job_apply/cheerio_job_app_list.js:29:17
at fn (/Users/Snark/node_modules/async/lib/async.js:746:34)
at /Users/Snark/node_modules/async/lib/async.js:1212:16
at /Users/Snark/node_modules/async/lib/async.js:166:37
at /Users/Snark/node_modules/async/lib/async.js:706:43
at /Users/Snark/node_modules/async/lib/async.js:167:37
at /Users/Snark/node_modules/async/lib/async.js:1208:30
at Request._callback (/Users/Snark/Dev/job_apply/cheerio_job_app_list.js:21:6)
at Request.self.callback (/Users/Snark/node_modules/request/request.js:198:22)
at emitTwo (events.js:87:13)
And this is js code.
var request = require("request"),
cheerio = require("cheerio"),
jsonfile = require("jsonfile"),
fs = require("fs"),
async = require("async");
var info = {},
dbArray = [];
var url = "http://udb.kr/local/category/390101?page=";
async.timesSeries(1166, function(n, next) {
var page = n + 1
async.waterfall([
function(callback) {
request(url + page, function(error, response, html) {
if (error) {
throw error
};
var $ = cheerio.load(html),
tObj = $('tbody tr td');
callback(null, tObj);
});
},
function(tObj, callback) {
for (var m = 0; m < 150; m = m + 5) {
if (tObj[m]) {
info.NM = tObj[m].firstChild.children[0].data
} else {
info.NM = null
};
if (tObj[m + 1].children != 0) {
info.nAddr = tObj[m + 1].firstChild.data
} else {
info.nAddr = null
};
console.log(info.NM);
dbArray.push(info);
}
callback(dbArray, callback);
},
function(dbArray, callback) {
fs.appendFile('./jobDB_l.json', JSON.stringify(dbArray), function (err) {
if (err)
throw err;
});
callback(null, 'done');
}
], function(err, result) {
console.log('----- ' +page+ '-----');
});
next(null, 'done');
}, function(err, result) {
console.log(result)
});
To get these to work together where you are using waterfall inside of each timesSeries iteration, you need to call the timesSeries done callback from the completion callback for the waterfall call. Right now, you are calling it long before that which means that timesSeries won't wait for the waterfall to be done.
You can do that by changing this:
], function(err, result) {
console.log('----- ' +page+ '-----');
});
next(null, 'done');
to this:
], function(err, result) {
console.log('----- ' +page+ '-----');
next(null, 'done');
});
It also seems odd that you have a hard-coded for loop limit of m < 150 rather than using the actual length of the content. You can easily run off the end of the content and potentially cause problems.
And, your error handling probably won't work well either. If you throw inside of the async request() callback, that's not going to go anywhere. You need much better error handling such as calling callback(error) to pass the error on to async.waterfall().
You also may want to surround all your DOM walking in a try/catch so if you throw any exceptions there, you can catch them yourself, analyze them and then fix the code.
if (tObj[m+1] && tObj[m+1].children != 0)