async.forEach(vsr.vehicles, function(vsr_vehicle, callback){
pjCustom.vehicleJson(vsr_vehicle, function(vehicleInitialize){
Vehicle.find({ where: { vehicleID: (vsr_vehicle.vehicleID).toString().trim() } }).success(function(vehicleFound){
if(vehicleFound){
//Code Logic is working fine.
}else{
vehicleBuild.save().success(function(vehicleNew){ // To create new vehicle of updated vsr
var vehicleBuild = Vehicle.build(vehicleInitialize)
pj.log("Update vehicle ............................")
temp.push(vehicleNew.vehicleID)
})
}
})
})
callback()
},function(){
res.send(204)
})
//vehicleJSON
exports.vehicleJson = function(vsr_vehicle, callback){
pjCustom.getVehicle(vsr_vehicle, function(status, vehicleId){
if (status == true) {
vsr_vehicle.vehicleID = vehicleId
callback(
{ 'vehicleID':vsr_vehicle.vehicleID).toString().trim(),'vsr_id':vsr_vehicle.vsr_id})
}
})
}
//getvehicle
exports.getVehicle = function(vsr_vehicle, callback){
if(vsr_vehicle.vehicleID !== undefined){
callback(true, vsr_vehicle.vehicleID)
}else{
Vehicle.find({ where: { 'vsr_id': vsr_vehicle.vsr_id },
attributes: ['id', 'vehicleID'],'order': 'id DESC', 'limit': '1'
}).success(function(vehicles){
var temp = (vehicles.vehicleID).split("-")
var newvehicleId = temp[0]+"-"+temp[1]+"-"+(parseInt(temp[2])+1)
callback(true, newvehicleId)
})
}
}
Explanation:
while inserting a record from vsr_vehicle. I need to check whether the vehicleID is present then it will fetch if not it will creates a new Id.
Consider this code is for updating a vehicle as well as inserting another "two" new vehicles. how to manage async process. of insertion of new vehicles.
it is not waiting for completion of first iteration and going for vehicleJson and generating same vehicleID for both new vehicles. suggest me to complete this challange.
My Code is clearly written here.
Please requesting before reading pls copy the code and paste in any JS editor you definitely will understand more than my explanation.
Your callback call in series.forEach is at the incorrect place. Here is the correction:
async.forEach(vsr.vehicles, function(vsr_vehicle, callback){
pjCustom.vehicleJson(vsr_vehicle, function(vehicleInitialize){
Vehicle.find({ where: { vehicleID: (vsr_vehicle.vehicleID).toString().trim() } }).success(function(vehicleFound){
if(vehicleFound){
callback(); // <--- call here
}else{
vehicleBuild.save().success(function(vehicleNew){ // To create new vehicle of updated vsr
var vehicleBuild = Vehicle.build(vehicleInitialize);
pj.log("Update vehicle ............................");
temp.push(vehicleNew.vehicleID);
callback(); // <--- call here
});
}
});
});
// callback(); // <--- Don't call here
},function(){
res.send(204);
});
BTW, for good practice, use semicolon (";") at the end of javascript statements
Related
I have an async.eachSeries() function which process a list of objects. After the list I want a res.send() function so I can send the result back to the frontend.
But I'm getting a
'Can't set headers after they are sent'
error on the res.send() line, which it's looks that the function is called before the list is completely processed.
module.exports.createOrder = function(req,res){
console.log("CreateOrder");
var orderDescription = "";
var payId = new ObjectId(); //create one id, to pay multiple orders at one time
var shopList = groupByShop(req.body.cart);
var orders = [];
var result = {};
console.log("before async");
//the cart is now sorted by shop, now we can make orders for each shop
async.eachSeries(Object.keys(shopList), function(key, callback){
console.log("in async");
var shop = shopList[key];
console.log("before saveOrder");
saveOrder(payId, shop, key, req.body, req.user, function(err, newOrder){
console.log("in saveorder");
if(err){
console.log("Err", err);
callback(err);
}else{
console.log("order saved");
orders.push(newOrder);
callback();
}
})
}, function(err){
if(err){
console.log("One or more orders are not saved:", err);
return res.status(400).json(err);
}else{
console.log("All orders are processed");
result = {
message: 'OK',
order: {
payId: orders[0].payId
}
};
return res.send(200).json(result);
}
})
}
What is going wrong here? Currently testing with one object in the 'shopList', and all log lines are visible in the server console.
When I remove the line, the function is working fine, but, of course, he is not sending any results. I also tried to move the line outside the function, but that cause, of course again, in a empty result{} and a sending before the function is done.
res.send(200) will send a HTML response with content '200' - what you want to do is res.status(200).json(result) although res.json(result) should also work fine.
I am pretty new to Node.js or Javascript in general when it comes to serverside stuff. Currently I am tring to validate some of the user input and set default values if something is wrong. Now if I run my validation the json object appears in the database befor my validation is completed.
The way I am doing the validation isnt maybe the best right now but if someone can explain me the behavior, I am pretty sure i can understand Javascript alot better in the future.
Is there a better way of doing validation (without mongoose or other ODM modules) with callbacks, middleware or should I use some async module?
Here is my code:
module.exports = function(app, express, todoDB, listDB, statusDB) {
var moment = require('moment');
var todoRouter = express.Router();
todoRouter.post('/', function(req, res, next) {
console.log('1');
if (!(moment(req.body.createDate).isValid())) {
req.body.createDate = moment().format("DD-MM-YYYY HH:mm:ss");
}
else {
req.body.createDate = moment(req.body.createDate).format("DD-MM-YYYY HH:mm:ss");
}
console.log('2');
if (req.body.list_id == '') {
listDB.findOne({list: 'Neu'}, function(reqdb, docs) {
if (docs == null) {
listDB.insert({list: 'Neu', index: 1});
listDB.findOne({list: 'Neu'}, function(reqdb, docs) {
console.log('AnlageListID');
console.log(docs._id);
req.body.list_id = docs._id;
});
}
else {
console.log('BestehendeListID');
console.log(docs._id);
req.body.list_id = docs._id;
}
});
}
console.log('3');
if (req.body.status_id == '') {
statusDB.findOne({status: 'offen'}, function(reqdb, docs) {
if (docs == null) {
statusDB.insert({status: 'offen', index: 1});
statusDB.findOne({status: 'offen'}, function(reqdb, docs) {
console.log('AnlageStatusID');
console.log(docs._id);
req.body.status_id = docs._id;
});
}
else {
console.log('BestehendeStatusID');
console.log(docs._id)
req.body.status_id = docs._id;
}
});
}
console.log('4');
console.log('StatusID');
console.log(req.body.status_id);
console.log('ListID');
console.log(req.body.list_id);
todoDB.insert({
todo: req.body.todo,
createDate: req.body.createDate,
endDate: req.body.endDate,
discription: req.body.discription,
comment: req.body.comment,
list_id: req.body.list_id,
priority_id: req.body.priority_id,
section_id: req.body.section_id,
user_id: req.body.user_id,
status_id: req.body.status_id,
company_id: req.body.company_id
});
res.json({message: 'TODO erfolgreich hinzugefĆ¼gt!'});
});
return todoRouter;
};
... and this is the ouput:
1
2
3
4
StatusID
ListID
POST /api/todos 200 76.136 ms - 44
BestehendeListID
M3Xh46VjVjaTFoCM
BestehendeStatusID
48v80B4fbO87c8um
PS: Its a small "project" just for me learing the MEAN Stack so I am using neDB.
If I understand correctly you try to sequentially execute a number of asynchronous calls and introduce checks in the code to validate if previous asynchronous calls have completed. This is not going to work in a general case because your checks may be processed before the asynchronous call goes through. It might work now and then just by chance, but I would not expect even that.
There are standard mechanisms for that. One of them is using promises, another one using async and yet another one if stacking up all callbacks one into another. Below I will demonstrate how to address the problem using async, but the same general idea applies to using promises. Check the async project on Github then the following part-solution will become clear:
var async = require("async")
async.waterfall([
function(next) {
listDB.findOne({list: 'Neu'}, next); // quits on error
},
function(doc, next) {
if (doc) {
return next(null, doc._id);
}
statusDB.insert({status: 'offen', index: 1}, function(err) {
if (err) return next(err); // quit on error
statusDB.findOne({status: 'offen'}, function(err, doc) {
next(err, doc._id); // quits on error
});
});
},
function(id, next) {
// do next step and so on
next();
}
],
// this is the exit function: it will get called whenever an error
// is passed to any of the `next` callbacks or when the last
// function in the waterfall series calls its `next` callback (with
// or without an error)
function(err) {
console.error("Error processing:", err)
});
I have a table where Persons are saved an their time (in seconds) where they were active.
I would like to write a function that gathers the total time in another table called gather.
For each row I am checking if an entry in the gather table exists. Depending on that result I make an insert or an update.
db.serialize(function() {
db.each("SELECT * from TEST", function(err, row) {
db.get("SELECT * from GATHER where name = " + row.name "", function(err, row) {
if(row === undefined || row === null){
var stmt = db.prepare("INSTER INTO gather (name, time) VALUE(?,?)");
stmt.run([name, seconds], function(error){
console.log('lastInsert ' + this.lastID);
});
stmt.finalize();
}else{
seconds += row.time;//increment time
var stmt = db.prepare("UPDATE gather SET time = ? WHERE name = ?");
stmt.run([seconds, row.name], function(error){
console.log('lastInsert ' + row.idProcessed);
});
stmt.finalize();
}
});
});
});
The problem that I ecounter is that sqlite runs asynchronously. Therefore multiple entries are created in my gather table although lines should be updated.
What would be the right way to run this function sychronously? Should I limit the lines and call the function every second or is there a smarted way?
You could use async. For example (but first you should read final notes at the end):
var async = require('async');
var data = {}
var yourFirstSelect() = function(callback){
//You do your first select
//...
db.get("SELECT * from TEST", function(err, row) {
if(row){
data.name = row.name;
data.otherInterestingAttribute = row.otherInterestingAttribute;
callback(err, data);
}else{
callback('Row is null');
}
})
//..
}
var yourSecondSelect() = function(data, callback){
//You do your second select
//...
db.get("SELECT * from GATHER where name = " + data.name "", function(err, row) { //Note that I'm using data instead of row
if(row){
data.seconds = row.seconds;
data.otherInterestingAttribute = row.otherInterestingAttribute;
callback(err, data);
}else{
callback('Row is null');
}
})
//..
}
var decide() = function(data, callback){
if (data.somethingExists) { //Do your validations
data.type = 'update';
callback(err, data);
} else {
data.type = 'insert';
callback(err, data);
}
}
var update() = function(data,callback){
if (data.type === 'update') {
//...
//Do your stuff in order to update
seconds += row.time;//increment time
var stmt = db.prepare("UPDATE gather SET time = ? WHERE name = ?");
stmt.run([seconds, row.name], function(error){
console.log('update ' + row.idProcessed);
});
stmt.finalize();
//...
} else {
callback(err,data);
}
}
var insert() = function(data,callback){
if (data.type === 'insert') {
//...
//Do your stuff in order to insert
var stmt = db.prepare("INSTER INTO gather (name, time) VALUE(?,?)");
stmt.run([data.name, data.seconds], function(error){
console.log('lastInsert ' + this.lastID);
callback(err,data);
});
stmt.finalize();
//...
} else {
callback(err,data);
}
}
var niceWorkflow = function(){
async.waterfall([
yourFirstSelect,
yourSecondSelect,
decide,
update,
insert
],
function (err, result) {
console.log('Done');
})
}
//and call your workflow
niceWorkflow();
Off course this is not a 100% working code, I wrote it in order you look another way to do what you are trying. Many variables, validations and more are just examples and I intentionally forgot the db.each to avoid being too extense and confusing you and trying to answer your final question Is there a smarter way?.
You can also use Q.all from Q library.
It will return a promise after all the promises are resolved. It one promise fails, then Q.all will be rejected.
I aim to import large amount of data by Mongoose. As a newbie, I fail to setup the flow control properly with various mechanisms by async. Glad if someone could point to an appropriate solution. Thanks.
var async = require('async'),
mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Cat = mongoose.model('Cat', { name: String });
// Imagine this is a huge array with a million items.
var content = ['aaa', 'bbb', 'ccc'];
var queries = [];
content.forEach(function(name) {
queries.push(function(cb) {
var obj = new Cat({ name: name });
obj.save(function(err) {
console.log("SAVED: " + name);
console.log(err);
});
return true;
});
});
// FAILED: async.parallel adds all content to db,
// but it would exhaust the resource with too many parallel tasks.
async.parallel(queries, function(err, result) {
if (err)
return console.log(err);
console.log(result);
});
// FAILED: save the first item but not the rest
async.waterfall(queries, function(err, result) {
if (err)
return console.log(err);
console.log(result);
});
// FAILED: same as async.waterfall, async.queue saves the first item only
var q = async.queue(function(name, cb) {
var obj = new Cat({ name: name });
obj.save(function(err) {
console.log("SAVED: " + name);
console.log(err);
});
})
q.push(content, function (err) {
console.log('finished processing queue');
});
I think eachLimit or eachSeries fit your situation best:
var content = ['aaa', 'bbb', 'ccc'];
async.eachLimit(content, 10, function(name, done) {
var obj = new Cat({ name : name });
obj.save(done);
// if you want to print some status info, use this instead:
//
// obj.save(function(err) {
// console.log("SAVED: " + name);
// console.log(err);
// done(err);
// });
//
}, function(err) {
// handle any errors;
});
With eachLimit, you can run an X amount of queries 'in parallel' (10 in the example above) to speed things up without exhausting resources. eachSeries will wait for the previous save before it continues with the next, so effectively saving one object at a time.
Notice that with each*, you won't get a list with (saved) objects back (it's a bit of a fire-and-forget mechanism where you're not interested in the outcome, bar any errors). If you do want a list of saved objects in the end, you can use the equivalent map* functions: mapLimit and mapSeries.
Check below algorithm...
users = getAllUsers();
for(i=0;i<users.length;i++)
{
contacts = getContactsOfUser(users[i].userId);
contactslength = contacts.length;
for(j=o;j<contactsLength;j++)
{
phones = getPhonesOfContacts(contacts[j].contactId);
contacts[j].phones = phones;
}
users[i].contacts = contacts;
}
return users;
I want to develop such same logic using node.js.
I have tried using async with foreach and concat and foreachseries functions. But all fail in the second level.
While pointer is getting contacts of one user, a value of i increases and the process is getting started for next users.
It is not waiting for the process of getting contacts & phones to complete for one user. and only after that starting the next user. I want to achieve this.
Actually, I want to get the users to object with proper
Means all the sequences are getting ruined, can anyone give me general idea how can I achieve such a series process. I am open to change my algorithm also.
In node.js you need to use asynchronous way. Your code should look something like:
var processUsesrs = function(callback) {
getAllUsers(function(err, users) {
async.forEach(users, function(user, callback) {
getContactsOfUser(users.userId, function(err, contacts) {
async.forEach(contacts, function(contact, callback) {
getPhonesOfContacts(contacts.contactId, function(err, phones) {
contact.phones = phones;
callback();
});
}, function(err) {
// All contacts are processed
user.contacts = contacts;
callback();
});
});
}, function(err) {
// All users are processed
// Here the finished result
callback(undefined, users);
});
});
};
processUsers(function(err, users) {
// users here
});
You could try this method without using async:
function getAllUserContacts(users, callback){
var index = 0;
var results = [];
var getUserContacts = function(){
getContactsOfUser(users[index].userId, function(contacts){
var index2 = 0;
var getContactsPhones = function(){
getPhonesOfContacts(contacts[index2].contactId, function(phones){
contacts[index2].phones = phones;
if(index2 === (contacts.length - 1)){
users[index].contacts = contacts;
if(index === (users.length - 1)){
callback(users)
} else {
index++;
getUserContacts();
}
}else{
index2++;
getContactsPhones();
}
});
}
getContactsPhones();
});
}
getUserContacts();
}
//calling the function
getAllUsers(function(users){
getAllUsersWithTheirContacts(users, function(usersWithContacts){
console.log(usersWithContacts);
})
})
//Asynchronous nested loop
async.eachSeries(allContact,function(item, cb){
async.eachSeries(item,function(secondItem,secondCb){
console.log(secondItem);
return secondCb();
}
return cb();
},function(){
console.log('after all process message');
});