Express.js- Calling three Dependent MongoDB queries sequentially for each loop - javascript

I have to insert multiple different JSON objects in MongoDB and then check whether the some of the data already exist in the database and run another query based on whether the data exists or not for each JSON Object. How can I do in expressjs? I am using mongojs package for working with MongoDB. The code I typed is below:
app.post('/addcard/:id', function(req, res) {
console.log("Received Add Card Request");
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var yrval = req.body.yrval;
var monval = req.body.monval;
var dateval = req.body.dateval;
for (var i=0;i<req.body.phone.length;i++){
//console.log(i);
var card = new Card({
cardType : req.body.cardtype,
cardTitle : req.body.cardtitle,
allowMultipleStore : false,
phoneNumber : req.body.phone[i],
messageUser : req.body.message,
expiryDate : new Date(year+yrval,month+monval,day+dateval),
creditPoints : req.body.creditpoints,
punchCount : req.body.punch,
messageReachPunchLimit : req.body.limitmessage,
merchantUsersId : mongoose.Types.ObjectId(req.body.merchantuserid),
merchantId : mongoose.Types.ObjectId(req.params.id)
});
console.log(card);
db.carddata.insert(card, function (err,docInserted){
// console.log(card);
console.log(i);
if (err) throw err;
db.userdata.find({phoneNumber:req.body.phone},function (err,docs){
console.log("hiss");
if (err) throw err;
if (docs.length!=0){
var carduser = new CardUsersAssignment({
cardId : docInserted._id,
userId : docs[0]._id,
remainingCreditPoints : req.body.creditpoints,
remainingPunchCount : req.body.punch
});
db.carduser.insert(carduser,function (err){
console.log(" Card Details saved successfully_existing");
//console.log(i);
})
}//If (docs.length!=0)
else{
console.log(" Card Details saved successfully");
}
})//Finding by PhoneNumber
console.log(i+1);
})//Insert Function
console.log("hi");
} // End of For Loop
res.json({
success:true,
message:"Hello. You did it!"
});
});
This code is written as if I were writing for sequential execution. I know that NodeJS is asynchronous. I tried async.waterfall but it is giving error with the mongodb query function. Any help would be great. I am a NodeJS noob. Links to article which discuss similar scenarios would also be great.

You can achieve this using async library.
There is two way to do it.
Use async each to iterate your data and inside each check data is first check data is already exist or not, based on find result you can return or insert the doc.
It is the same as 1st, the only different is you just can to use waterfall for find and insert.
First Approach:
async.each(req.body.phone, function(data, callback) {
// Create card Info
db.carddata.insert(card, function (err,docInserted){
if (err) {throw err;}
db.userdata.find({phoneNumber:req.body.phone},function (err,docs){
if (err) {throw err;
} else if ( docs.length ){
// create carduser data
db.carduser.insert(carduser,function (err){
if (err) {throw err;}
callback();
}
} else {
console.log(" Card Details saved successfully");
callback();
}
}
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
Second Approach:
async.each(req.body.phone, function(data, callback) {
//create card data
let data = {}
data.phone = req.body.phone;
data.docInserted = data.docInserted;
data.cardata = cardData;
async.waterfall([
insertCard,
updateDataFind,
cardDataInsert,
async.apply('insertCard', data)
], function (err, result) {
if(err){
if(err.success){
callback();
}
throw err;
}
callback();
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function insertCard(data, callback){
db.carddata.insert(card, function (err,data.docInserted){
if(err){throw err;}
callback(null, data);
}
}
function updateDataFind(data, callback){
db.userdata.find({phoneNumber:data.phone},function (err,docs){
if (err) {throw err;}
else if (docs.length!=0){ callback(null, data); }
else { callback({success:true}) }
}
}
function cardDataInsert(data, callback){
// create card user or pass from data.
db.carduser.insert(carduser,function (err){
if (err) {throw err;}
callback(null, data);
}
}

Related

NodeJS Html-pdf: fs.readfilesync how to async/await

I have a problem with my html-pdf document creation. The problem is that often the code runs to fast to complete the process of pdf-docutment creation. The Processes consists out of building an HTML-String by replacing placeholders in an Html file. Below you see the code what happens afterwards.
Object.keys(setter).forEach(function(element, key, _array) {
var regex = new RegExp(element, "g");
data = data.replace(regex, setter[element])
})
var result = data;
fs.writeFile(mergeFileRes, result, 'utf8', function (err) {
if(err) {
console.log(err);
return;
} else {
let html2 = fs.readFileSync(mergeFileRes, 'utf8');
let options = {
format: 'a4' ,
"directory" : "/tmp",
};
if(html2){
pdf.create(html2, options).toStream(function(err, stream2){
if(err) console.log(err);
stream2.pipe(res);
stream2.on('end', function () {
try{
fs.unlink(mergeFileRes)
console.log(3090, "deleted file");
}
catch (err){
console.log(3090, "Did not delete file");
}
});
});
} else {
}
}
});
My problem is that in many cases the html2 variable is not yet created before the pdf.create process starts. This is probably because the readFileSync takes too long to finish.
I was wondering, how can I fix this. How can I make the pdf.create wait for the readFileSync to finish and the html2 variable to be filled.
You can use fs.readFile to read the file asynchronously and html2 will be available within the callback function.
Object.keys(setter).forEach(function(element, key, _array) {
var regex = new RegExp(element, "g");
data = data.replace(regex, setter[element])
})
var result = data;
fs.writeFile(mergeFileRes, result, 'utf8', function (err) {
if(err) {
console.log(err);
return;
} else {
fs.readFile(mergeFileRes, 'utf8', function(err, html2){
if (err) throw err;
let options = {
format: 'a4' ,
"directory" : "/tmp",
};
pdf.create(html2, options).toStream(function(err, stream2){
if(err) console.log(err);
stream2.pipe(res);
stream2.on('end', function () {
try{
fs.unlink(mergeFileRes)
console.log(3090, "deleted file");
}
catch (err){
console.log(3090, "Did not delete file");
}
});
});
});
}
});

How to turn a query result into a js variable (Javascript)

I've been searching for this for a day now and I'm basically hopeless.
All I want to do is export the query result as a string (so dataString basically) so I can import as a string in my external .js file.
module.exports.getKlanten = function(req, res){
console.log("zoekt naar klanten");
pool.connect(function(err, client, done){
if(err){
return console.error('error fetching client from pool', err);
}
client.query("select * from abc.relations limit 5", function(err,result){
done();
if(err){
return console.error('error running query', err);
}
var dataString = JSON.stringify(result.rows);
var count = Object.keys(result.rows).length;
var klanten = result.rows;
res
.status(200)
.render("index", {dataString: dataString, klant: klanten, count: count});
console.log("done");
})
});
}
And what would I have to do in the js file to import the string then? It looks so easy yet I can't seem to get it right.
It would be something like this
module.exports.getKlanten = function(req, res){
console.log("zoekt naar klanten");
return "Hello world"; }
and then in your external .js file, you can import it like this
const myModule = require('./JSFile');
and use it like this
console.log(myModule.getKlanten());
Also, use a return statement so that you have a string in your variable.
I am assuming that you need to use the same function externally somewhere else and also for http handler so split it into three files.
//getKlanten.js
module.exports.getKlanten = function(){
return new Promise(function (resolve, reject) {
pool.connect(function(err, client, done){//make sure pool is avialble here
if(err){
console.error('error fetching client from pool', err);
reject(err);
}
client.query("select * from abc.relations limit 5", function(err,result){
if(err){
console.error('error running query', err);
reject(error);
}
var dataString = JSON.stringify(result.rows);
var count = Object.keys(result.rows).length;
var klanten = result.rows;
var data = {dataString: dataString, klant: klanten, count: count}
resolve(data);
})
});
})
}
//in external.JS
var getKlanten = require('getKlanten');
getKlanten().then(function(object) {
console.log(object);
}, function(err){
console.log(err);
})
//in http handler file
var getKlanten = require('getKlanten');
module.exports = function(req,res) {
getKlanten().then(function(data) {
res
.status(200)
.render("index", data);
});
}

synchronize and serialize function or tasks on node js

i am stacking on this problem since a week, it's a problem of synchronize on Node JS.
The process that I want to do is :
1- check the existence of table (collection). --> if not insertion of data
2- if the table was created, then i have to find all data on table and compare it with the data that i want to insert.
3- if the new data is already exist on the database (table) the program doesn't do any thing, if not the program inserts the new data to the the database (table).
So we have 3 functions should be scheduled.
function 1
var getCollection = function(collection, new_theme, nbr_indicateur,callback) {
dbObject.listCollections().toArray(function(err, collections){
if ( err ) throw err;
assert.equal(err, null);
collections.forEach(function(collect){
if(collect.name == collection)
{
callback(true);
}
else {
dbObject.collection(collection).insertOne( {
"name_theme" : new_theme,
"nbr_indicateur" : nbr_indicateur
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the Table_Mapping_Theme collection.");
});
callback(false);
}
});
});
};
function 2 :
var getData = function(value, collection, theme, callback) {
var clb = true;
if(value)
{
dbObject.collection(collection).find({}).toArray(function(err, docs){
if ( err ) throw err;
assert.equal(err, null);
docs.forEach(function(doc){
if(doc.name_theme == theme)
{
console.log("ce theme existe déja");
clb = false;
}
});
});
}
callback(clb);
};
function 3 :
var insertData = function(value, collection, new_theme, nbr_indicateur, callback) {
if(value)
{
dbObject.collection(collection).insertOne( {
"name_theme" : new_theme,
"nbr_indicateur" : nbr_indicateur
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the "+collection+" collection.");
});
}
callback("done");
};
calling those functions (app.post using express js)
here i tried with pyramid method but it doesn't work
app.post('/setting/add_theme', urlencodedParser, function(req, res) {
getCollection('Table_Theme', req.body.new_theme, req.body.nbr_indicateur, function(value0){ console.log("0"+value0);
getData(value0,'Table_Theme', req.body.new_theme, function(value1) { console.log("1"+value1);
insertData(value1, 'Table_Theme', req.body.new_theme, req.body.nbr_indicateur, function(value2){ console.log("2"+value2);
});
});
});
res.redirect('/setting');
});

async.each cannot set headers after already set

Here's what happening. I'm saving new companies first, then attaching the _id to each new user before they get saved. The issue I'm running into is returning a response. When I put the res.json() into the function thats getting repeated obviously I'm getting an error because I already have a response sent from the first time it loops through.
So, How do I call signupSeq(record, res) but wait for the async methods to finish so I know whether I have an error or not?
var signupSeq = function(req, res) {
async.waterfall([
function(callback) {
console.log(req);
if (req.company._id===undefined){
var company = new Company(req.company);
company.save(function(err){
if (err) {
console.log('save error');
callback(err);
}else{
callback(null, company._id);
}
})
}else{
callback(null, req.company._id); //pass teh plain ID if it's not a new name:xxx
}
},
function(companyId, callback) {
delete req.company
req.company = companyId
// Init Variables
var user = new User(req);
var message = null;
// Add missing user fields
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
// Then save the user
user.save(function(err) {
if (err) {
callback(err);
} else {
callback(null, user);
}
});
}
], function (err, result) {
if(err){
console.log(result+'funciton result')
return err
// res.status(400).send({
// message: errorHandler.getErrorMessage(err)
// });
}else{
console.log(result+'funciton result')
return result
//res.json(result)
}
});
}
exports.saveMany = function(req, res){
async.each(req.body, function(record, callback) {
// Perform operation on record.body here.
console.log('Processing record.body ' + record);
// Do work to process record.body here
var x = signupSeq(record, res)
console.log(x+'<<<<<<<value of x');
console.log('record.body processed');
callback();
}, function(err){
// if any of the record.body processing produced an error, err would equal that error
if( err ) {
res.json(err);
// One of the iterations produced an error.
// All processing will now stop.
console.log('A record.body failed to process');
} else {
res.json('Success');
console.log('All files have been processed successfully');
}
});
}
You could add a callback (cb) in your signupSeg function.
var signupSeq = function(req, res, cb) {
async.waterfall([
function(callback) {
console.log(req);
if (req.company._id===undefined){
var company = new Company(req.company);
company.save(function(err){
if (err) {
console.log('save error');
callback(err);
}else{
callback(null, company._id);
}
})
}else{
callback(null, req.company._id); //pass teh plain ID if it's not a new name:xxx
}
},
function(companyId, callback) {
delete req.company
req.company = companyId
// Init Variables
var user = new User(req);
var message = null;
// Add missing user fields
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
// Then save the user
user.save(function(err) {
if (err) {
callback(err);
} else {
callback(null, user);
}
});
}
], function (err, result) {
if(err){
console.log(result+'funciton result')
cb(err)
// res.status(400).send({
// message: errorHandler.getErrorMessage(err)
// });
}else{
console.log(result+'funciton result')
cb(null,result)
//res.json(result)
}
});
}
exports.saveMany = function(req, res){
async.each(req.body, function(record, callback) {
// Perform operation on record.body here.
console.log('Processing record.body ' + record);
// Do work to process record.body here
signupSeq(record, res,function(err,result){
var x= result;
console.log(x+'<<<<<<<value of x');
console.log('record.body processed');
callback();
})
}, function(err){
// if any of the record.body processing produced an error, err would equal that error
if( err ) {
res.json(err);
// One of the iterations produced an error.
// All processing will now stop.
console.log('A record.body failed to process');
} else {
res.json('Success');
console.log('All files have been processed successfully');
}
});
}
This way inside the asyn.each the signipSeg will have to finish before the call of the callback().
Hope this helps.

How to wait for a response from a mongo findOne query in a node/express app before using the response in following control flow

I am new to node, and also JavaScript callbacks.
I am trying to check if an account exists in mongo and then 'save it' if it doesn't and return an error if it does.
I am currently trying to figure this out outside of my express app. This is what i have..
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (doc) {
if(doc) {
console.log('account exists');
} else {
console.log('good to go');
}
console.dir(doc);
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
if(err) throw err;
db.close();
callback();
});
}
with the console.dir(doc); above returning as undefined. How do I wait for the findOne to return before using the callback to console.log or save the account?
The reason you are getting undefined is because when you call your callback your are not passing it the doc. That line should look like callback(doc).
Here is an updated version of your code with a few suggestions:
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (err, doc) {
if(err) {
// something went wrong
console.log(err);
return;
}
if(doc) {
console.log('account exists');
console.dir(doc);
} else {
console.log('good to go');
}
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
db.close();
if(err) {
// don't use throw when in async code
// the convention is to call your callback with the error
// as the first argument (notice that I added an argument
// to the definition of your callback above)
callback(err);
}
else {
// call your callback with no error and the data
callback(null, doc);
}
});
}

Categories

Resources