The code is for handling the POST request within Expressjs and mongodb
router.post('/', function(req, res){
var data = req.body;
Tag.find({name: data.name}).limit(1).exec( function(err, result){
if(err){
} else {
if(result.length > 0){ // Already exist a tag with same name
res.status(400).end('Already exist!');
} else { // Save the new Tag to database
var tag = new Tag();
tag.name = data.name;
tag.lastModifier = req.user?req.user.username:"system";
tag.lastModified = Date.now();
tag.save(function(err){
if(err){
res.status(400).json({
message: "insert tag error"
});
} else {
Tag.findOne(tag, function(err, result){
if(err){
res.status(400).json({
message: "some error.."
});
} else {
//res.status(400).end('same tag name');
res.status(201).json({
_id: result._id
});
}
});
}
});
}
}
});
});
The stairs in the last 9 lines are terrible....please teach me how could I make this mess clearer?
You can use named functions instead of some of the function expressions:
router.post('/', function(req, res){
var data = req.body;
Tag.find({name: data.name}).limit(1).exec( function(err, result){
if(err){
} else {
if(result.length > 0){ // Already exist a tag with same name
res.status(400).end('Already exist!');
} else { // Save the new Tag to database
var tag = new Tag();
tag.name = data.name;
tag.lastModifier = req.user?req.user.username:"system";
tag.lastModified = Date.now();
tag.save(save(err));
}
}
});
});
function save(err){
if(err){
res.status(400).json({
message: "insert tag error"
});
} else {
Tag.findOne(tag, handleResult(err, result));
}
}
function handleResult(err, result){
if(err){
res.status(400).json({
message: "some error.."
});
} else {
//res.status(400).end('same tag name');
res.status(201).json({
_id: result._id
});
}
}
(You can surely name them a little more appropriate for the situation, but it shows the principle.)
router.post('/', function(req, res){
var data = req.body;
Tag.find({name: data.name}).limit(1).exec(cbExec);
});
function cbExec(err, result){
if(err){
} else {
if(result.length > 0){ // Already exist a tag with same name
res.status(400).end('Already exist!');
} else { // Save the new Tag to database
var tag = new Tag();
tag.name = data.name;
tag.lastModifier = req.user?req.user.username:"system";
tag.lastModified = Date.now();
tag.save(cbSave);
}
}
}
function cbSave(err){
if(err){
res.status(400).json({message: "insert tag error"});
} else {
Tag.findOne(tag, cbTag);
}
}
function cbTag(err, result){
if(err){
res.status(400).json({message: "some error.."});
} else {
//res.status(400).end('same tag name');
res.status(201).json({_id: result._id});
}
}
I really recommend you to try promises. There are many implementations available for JavaScript and Node.js.
A promise basically encapsulates an asynchronous operation into a value, which allows you to get rid of these horrible nested callbacks. They also allow you to chain asynchronous operations more easily.
What you're forced to do in your callback-based code is to check errors at every level, which can get rather tedious if your error handling could be at one place. Promises will propagate the error, allowing easy handling in one place.
Here are some references:
http://www.html5rocks.com/en/tutorials/es6/promises/
https://developer.mozilla.org/cs/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://www.promisejs.org/
It might take a little while to adjust to using them, but trust me, it is absolutely worth it.
You can separate the cod a little bi more. Instead of creating lambda functions create normal ones. You can get rid of one pair of braces in 4th line
if(err){
} else {
using if(!err)
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();
}
});
}
thank you for taking the time to read my question.
I have an array with records that I want to put into MYSQL database from NodeJS. These records have a jobkey field that I want to be UNIQUE, but I don't want it to be the PRIMARY KEY since the jobkey coming from an API and I want to use my own recid for better indexing and sorting.
I am using NodeJS to first check if the jobkey exists by doing a SELECT WHERE and checking if rows.length > 0? then adding the job if jobkey does not already exist. For some reason I keep getting a ER_DUP_ENTRY error and I can't figure out why my rows.length sometimes === 0 even though the jobkey exists. I have been hitting my head against the wall now for a few days. I hope it's not just a semi-colon or one of those simple errors I have overlooked. Anyways I need help please look at my code.
function is_job_key(_jobkey, cb){ // cb(err, flag)
var sql = 'SELECT * FROM tbl_indeed WHERE ?';
conn.query(sql, {jobkey: _jobkey}, function(err, rows){
if(err){
console.log(err);
return cb(true);
}
bar.tick();
if(rows.length > 0){ // jobkey exists
return cb(null, true);
}
cb(null, false);
});
}
function insert_job(posts, cb){ // cb(err)
var sql = 'INSERT INTO tbl_indeed SET ?';
conn.query(sql, posts, function(err, result){
if(err){
console.log(err);
return cb(true);
}
bar.tick();
cb(null);
});
}
function insert_all_jobs(job_arr, query_str, cb){ // cb(err, count_inserted)
function get_posts(job){
var posts = {jobkey: job.jobkey, snippet: job.snippet, url: job.url, jobtitle: job.jobtitle, company: job.company, date: job.date, query_string: query_str};
return posts;
}
bar = new progress(' ' + query_str + ' (:current / :total) [:bar] :percent :etas', {
complete: '=',
incomplete: ' ',
width: 40,
total: job_arr.length*2
});
var count_inserted = 0;
async.each(job_arr, function(job, cb){
var posts = get_posts(job);
is_job_key(job.jobkey, function(err, result){
if(err) return cb(true);
if(result){
bar.tick();
return cb(); // jobkey exists
}
insert_job(posts, function(err){
if(err) return cb(true);
count_inserted++;
cb();
});
});
}, function(err){
if(err) return cb(true);
console.log('done');
conn.end();
cb(null, count_inserted);
});
}
var job_arr = JSON.parse(fs.readFileSync('technician.txt', 'utf-8'));
//job_arr = job_arr.splice(1, 10); //for some reason this works ok...
insert_all_jobs(job_arr, 'technician', function(err, result){
if(err) return console.log('error');
console.log(result);
});
thank you for reading my question and have a lovely day
~A
I am using Mongodb and the findOne feature:
User.findOne({$or: [{email: req.body.email}, {mobile: req.body.mobile}]}
However the issue I am facing is with req.body.email and req.body.mobile - in certain cases can be empty.
I have initially solved this using:
var toSearchSmartString = {$or: [{email: req.body.email}, {mobile: req.body.mobile}]};
if (req.body.email.length == 0) {
toSearchSmartString = {mobile: req.body.mobile};
} else if (req.body.mobile.length == 0) {
toSearchSmartString = {email: req.body.email};
}
then in the findOne, simply using:
User.findOne(toSearchSmartString);
So I want to check is this 'safe' todo? The reason I ask is this safe is because if I don't set the default value for toSearchSmartString and instead set it at the end of the if block (in a else) I get 'undefined' for the string.
I'm concerned that the findOne method may use the default toSearchSmartString before the if else condition has been checked? Am I right to concerned about this?
Alternatively is there some Mongodb function I can use to solve?
UPDATE:
So after comments in answer below - having issues with the code:
I solved it by moving the var declaration above to where its used.
var contWithRegCallback = function(err, user) {
console.log(user);
}
if (req.body.email.length == 0) {
User.findOne({mobile: req.body.mobile}, contWithRegCallback);
} else if (req.body.mobile.length == 0) {
User.findOne({email: req.body.email}, contWithRegCallback);
} else {
User.findOne({$or: [{email: req.body.email}, {mobile: req.body.mobile}]}, contWithRegCallback);
}
Namely the user in the callback function keeps returning undefined. Shouldnt it be the contents fro the fineOne?
Why don't you just use conditional check?
This simple snippet should work as expected, notice, you want to filter by email or mobile.
var callback = function(err, result){
if(err) {
return res.status(400).send({message: 'Server error:' + JSON.stringify(err)});
} else {
res.json(result);
}
}
if (req.body.email){
User.findOne({email: req.body.email}, callback);
} else if (req.body.mobile) {
User.findOne({mobile: req.body.mobile}, callback);
} else {
return res.status(400).send({message: "Email or Mobile required"});
}
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 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.