before fetching data in db response is sent by node js - node.js

this is my set notification object
var sentNotificationObj = function (notification, eventid, addedorganizerpropic) {
this.notification = notification;
this.eventid = eventid;
this.addedorganizerpropic = addedorganizerpropic;
}
this is my array which is stored notification obect
var notificationSetArray2 = [];
this is my api of getnotification
router.post('/getnotification', function (req, res) {
console.log('in aside');
var id = req.body.userid;
console.log('pos id' + id);
User.findById({ _id: id }, function (err, result) {
if (err) {
console.log('err get notification');
res.statusCode = 500;
res.json({
success: false,
message: "severe error"
});
} else {
this is code fetchin data in data base
for (var i = 0; i < result.notification.length; i++) {
var addedevent = result.notification[i].addedevent;
var notification = result.notification[i].notification;
console.log('added event' + addedevent);
console.log('added noti' + notification);
User.findById({ _id: result.notification[i].addedorganizer }, function (err, addedorganizer) {
if (err) {
console.log('error get added user pofile pic');
} else {
convert image to base64
var base64str = base64_encode(addedorganizer.profileData.profileurl);
console.log(base64str);
console.log(notification);
console.log(addedevent);
var newsentNotificationObj = new sentNotificationObj(notification, addedevent, base64str);
notificationSetArray2.push(newsentNotificationObj);
console.log('succe get added user profile pic');
}
});
}
this is response
res.statusCode = 200;
res.json({
success: true,
notificationArray: notificationSetArray2
})
console.log(notificationSetArray2);
notificationSetArray2.length = 0;
}
});
});

The most simple solution in here to use async library here.
Node runs code in asynchronous way. So it is natural to send response before fetching any data from your database.
By using async you can execute this in a sequence. So it will be solved.
Use async.series method for solve this. For example
async.series(
[
function(callback){
// fetch your data here using mongo with your loop
//
//
callback(); // this will trigger next step (call this after you finished iterating array)
},
function(callback){
// after above code has been executed
// send response here
callback() // call this to proceed
}
],
function(err){
// handle any error in here
}
)
A good example of how to use asyncjs in node

Related

Http requests inside a for loop from angular to node.js API returns 404

I try to send several HTTP requests continuously inside a for loop to node.js rest API.
Below is how I try to send HTTP requests from my Angular Front-end.
getOthersCompletionsByTaskID is the function that send a HTTP request.
this.tasksService.getTasks().then(res=>{
let i=0;
for(i;i< this.tasksService.tasks.length; i++){
this.completionService.getOthersCompletionsByTaskID(this.tasksService.tasks[i].TaskId).then(res =>{
let cArray: any = res;
console.log("cArray ", cArray)
})
}
this.dtTrigger.next();
this.rendMyTasksTable();
})
Below is my query execution function in node API.
function queryGetExecute(qry, params, isMultiSet, callback) {
var data = [];
var dataset = [];
var resultset = 0;
request = new Request(qry, async function (err, rowCount) {
utility.sendDbResponse(err, rowCount, dataset, callback);
});
params.forEach( param => {
request.addParameter(param.name, param.type, param.val);
});
request.on('row', async function (columns) {
utility.buildRow(columns, data);
});
request.on('doneInProc', async function (rowCount, more, rows) {
if (isMultiSet == false) {
dataset = data;
} else {
dataset.push(data);
data = [];
}
});connection.execSql(request)}
Below is the function in the repository that calls the above function.
function getCompletionsByFirebaseId(req, res){
if (req.params.firebaseId && req.params.taskId) {
var parameters = [];
parameters.push({ name: 'firebaseId', type: TYPES.NVarChar, val: req.params.firebaseId});
parameters.push({ name: 'taskId', type: TYPES.NVarChar, val: req.params.taskId});
var query = "select users.[name], completedById, [status], completionImage,completionId,exchangeTaskId from Tasks join completions on Tasks.TaskId=completions.taskId join users on users.firebaseId = completions.completedById where taskownerId=#firebaseId and Tasks.TaskId = #taskId"
dbContext.getQuery(query, parameters, false, function (error, data) {
if (data) {
req.data = data[0];
let finaldata = res.json(response(data, error));
return finaldata
}else{
return res.sendStatus(404);
}
});
}else
{
return res.sendStatus(404)
}
}
When I do requests like this, API returns 404. but the first request is becoming successful. rest requests returning 404. What am I doing wrong here?

Saving MongoJS select result to an array in NodeJS and then modifying it

Having a hard time saving and modifying the result of a MongoJS query in NodeJS.
router.post('/getMySubjects', function (req, res) {
var data = [];
if (req.body.type == 'Professor') {
db.subjects.find({ contractorID: req.body.userId }, function (err, subjects) {
data = subjects; // SUBJECTS ARE NOW SAVED TO DATA SUCCESSFULLY
data.forEach(function(subject) {
db.faculties.find({ _id: mongojs.ObjectID(subject.subjectFor_faculty)}, function (err, faculty) {
subject.faculty = faculty; // BUT HERE I WANT TO ADD A FACULTY (object)
// BASED ON THE subjectFor_faculty (id)
// WHICH IS LOCATED IN EVERY (subject)
// ELEMENT IN DATA ARRAY
});
});
res.send(data); // THE DATA HERE IS UNMODIFIED
// SAME AS DATA ON LINE 6
});
}
});
I presume that I don't yet fully understand how the response works (btw the app is made with express framework), because when the data is first saved on line 6, the next step is sending the data, and only THEN the app goes goes into the forEach loop...
You are making async mongo queries. you have to make them work sync for getting right data. here's implementation using promises.
router.post('/getMySubjects', function (req, res) {
var data = [];
if (req.body.type == 'Professor') {
db.subjects.find({ contractorID: req.body.userId }, function (err, subjects) {
data = subjects;
var promises = [];
data.forEach(function(subject) {
var promise = new Promise(function(resolve, reject) {
db.faculties.find({ _id: mongojs.ObjectID(subject.subjectFor_faculty)}, function (err, faculty) {
resolve(faculty);
});
});
promises.push(promise);
});
Promise.all(promises).then(function(values){
for(var i = 0; i< values.length;i++){
data[i].faculty = values[i];
}
res.send(data);
});
});
}
});

Unable to access get method from request package in the function node

I have added request module and made changes in main settings.js as per the documentation :
// Anything in this hash is globally available to all functions.
// It is accessed as context.global.
// eg:
// functionGlobalContext: { os:require('os') }
// can be accessed in a function block as:
// context.global.os
functionGlobalContext: {
requestModule:require('request').defaults({jar: true})
// os:require('os'),
// octalbonescript:require('octalbonescript'),
// jfive:require("johnny-five"),
// j5board:require("johnny-five").Board({repl:false})
},
This is the code in one of my function nodes :
var request = context.global.requestModule;
request.get('http://192.168.0.44:3000' + '/api/stats',
function (err, data) {
if (err) {
console.log("could not process data");
}
else {
var body = JSON.parse(data.body);
msg.payload = body.deviceCount;
}
});
return msg;
My node red version is (0.16.2)
That won't work because you return msg before the async call back in the request object is called. The following should work:
var request = context.global.requestModule;
request.get('http://192.168.0.44:3000' + '/api/stats',
function (err, data) {
if (err) {
console.log("could not process data");
}
else {
var body = JSON.parse(data.body);
msg.payload = body.deviceCount;
node.send(msg)
}
});

node js mongo db dependencies (doc not being found)

I have the following code:
var method = PushLoop.prototype;
var agent = require('./_header')
var request = require('request');
var User = require('../models/user_model.js');
var Message = require('../models/message_model.js');
var async = require('async')
function PushLoop() {};
method.startPushLoop = function() {
getUserList()
function getUserList() {
User.find({}, function(err, users) {
if (err) throw err;
if (users.length > 0) {
getUserMessages(users)
} else {
setTimeout(getUserList, 3000)
}
});
}
function getUserMessages(users) {
// console.log("getUserMessages")
async.eachSeries(users, function (user, callback) {
var params = {
email: user.email,
pwd: user.password,
token: user.device_token
}
messageRequest(params)
callback();
}, function (err) {
if (err) {
console.log(err)
setTimeout(getUserList, 3000)
}
});
}
function messageRequest(params) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ params.email +"&api_password="+ params.pwd +"&method=getSMS&type=1&limit=5"
request(url, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
if (responseObject["status"] == "success") {
async.eachSeries(messages, function(message, callback){
console.log(params.token)
saveMessage(message, params.token)
callback();
}, function(err) {
if (err) {
console.log(err)
}
// setTimeout(getUserList, 3000)
})
} else {
// setTimeout(getUserList, 3000)
}
} else {
console.log(err)
// setTimeout(getUserList, 3000)
}
});
setTimeout(getUserList, 3000)
}
function saveMessage(message, token) {
// { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } }
// Message.find({ $and: [{ message_id: message.id}, {device_token: token}]}, function (err, doc){
Message.findOne({message_id: message.id}, function (err, doc){
if (!doc) {
console.log('emtpy today')
var m = new Message({
message_id: message.id,
did: message.did,
contact: message.contact,
message: message.message,
date: message.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: token
});
m.save(function(e) {
if (e) {
console.log(e)
} else {
agent.createMessage()
.device(token)
.alert(message.message)
.set('contact', message.contact)
.set('did', message.did)
.set('id', message.id)
.set('date', message.date)
.set('message', message.message)
.send();
}
});
}
}) //.limit(1);
}
};
module.exports = PushLoop;
Which actually works perfectly fine in my development environment - However in production (i'm using Openshift) the mongo documents get saved in an endless loop so it looks like the (if (!doc)) condition always return true therefore the document gets created each time. Not sure if this could be a mongoose issue - I also tried the "find" method instead of "findOne". My dev env has node 0.12.7 and Openshift has 0.10.x - this could be the issue, and i'm still investigating - but if anybody can spot an error I cannot see in my logic/code please let me know
thanks!
I solved this issue by using a "series" like pattern and using the shift method on the users array. The mongoose upsert findOneOrCreate is good however if there is a found document, the document is returned, if one isn't found and therefore created, it's also returned. Therefore I could not distinguish between the newly insert doc vs. a found doc, so used the same findOne function which returns null if no doc is found I just create it and send the push notification. Still abit ugly, and I know I could have used promises or the async lib, might refactor in the future. This works for now
function PushLoop() {};
var results = [];
method.go = function() {
var userArr = [];
startLoop()
function startLoop() {
User.find({},function(err, users) {
if (err) throw err;
users.forEach(function(u) {
userArr.push(u)
})
function async(arg, callback) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ arg.email +"&api_password="+ arg.password +"&method=getSMS&type=1&limit=5"
request.get(url, {timeout: 30000}, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
var status = responseObject.status
if (status === "success") {
messages.forEach(function(m) {
var message = new Message({
message_id: m.id,
did: m.did,
contact: m.contact,
message: m.message,
date: m.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: arg.device_token
});
var query = { $and : [{message_id: m.id}, {device_token: arg.device_token}] }
var query1 = { message_id: m.id }
Message.findOne(query).lean().exec(function (err, doc){
if (!doc || doc == null) {
message.save(function(e) {
console.log("message saved")
if (e) {
console.log("there is an error")
console.log(e)
} else {
console.log(message.device_token)
var messageStringCleaned = message.message.toString().replace(/\\/g,"");
var payload = {
"contact" : message.contact,
"did" : message.did,
"id" : message.message_id,
"date" : message.date,
"message" : messageStringCleaned
}
var note = new apns.Notification();
var myDevice = new apns.Device(message.device_token);
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.badge = 3;
note.alert = messageStringCleaned;
note.payload = payload;
apnsConnection.pushNotification(note, myDevice);
}
})
}
});
});
}
else {
console.log(err)
}
}
});
setTimeout(function() {
callback(arg + "testing 12");
}, 1000);
}
// Final task (same in all the examples)
function series(item) {
if(item) {
async( item, function(result) {
results.push(result);
return series(userArr.shift());
});
} else {
return final();
}
}
function final() {
console.log('Done');
startLoop();
}
series(userArr.shift())
});
}
}
module.exports = PushLoop;

Node.js - Query within a query, then render results using Express

I'm new to Node from the lands of C#, PHP and Python. I've been working days in many variations of the same problem - how can I retrieve a set of data, based on that data, retrieve another set, then render the results out. I've tried the method below, event based (client.on("row")) and the async module and I can't get any to produce the right results. In the end, I'd like to pass a projects object with tasks added to Express to render.
Could anyone help me out of this hole?
exports.index = function(req, res){
req.session.user_id = 1;
if (req.session == undefined || req.session.user_id == null || req.session.user_id < 0) {
res.redirect('/login');
} else {
var pg = require('pg');
var conString = "postgres://jason#localhost:5432/simpleproject";
var client = new pg.Client(conString);
client.connect(function(err) {
client.query("SELECT * FROM project", function(err, projects) {
for (var i=0; i<projects.rowCount; i++) {
var project = projects.rows[i];
client.query("SELECT * FROM task WHERE project_id="+projects.rows[i].id, function(err, subrows) {
if (subrows.rowCount > 0) {
project.tasks = subrows.rows;
console.log("adding tasks");
} else {
project.tasks = null;
}
if (i==projects.rowCount) {
console.log("rendering");
res.render('main', { title: 'My Projects', projects: projects });
}
});
}
if (err != null) { console.log(err); }
}
);
});
}
};
UPDATE: Meryn below provides a good solution to my issue, just to share that information, in the end, below his code with a little touch up to get it to operate: (thanks Meryn!)
var async = require('async');
exports.index = function(req, res){
req.session.user_id = 1;
if (req.session == undefined || req.session.user_id == null || req.session.user_id < 0) {
res.redirect('/login');
} else {
var pg = require('pg');
var conString = "postgres://jason#localhost:5432/simpleproject";
var client = new pg.Client(conString);
var addTasksToProject = function(projectRow, cb) { // called once for each project row
client.query("SELECT * FROM task WHERE project_id="+projectRow.id, function(err, result) {
console.log("tasks");
if(err) return cb(err); // let Async know there was an error. Further processing will stop
projectRow.tasks = result.rows;
cb(null); // no error, continue with next projectRow, if any
});
};
client.connect(function(err) {
client.query("SELECT * FROM project", function(err, projects) {
console.log("projects");
if (err) return console.error(err);
async.each(projects.rows, addTasksToProject, function(err) {
if (err) return console.error(err);
// all project rows have been handled now
console.log(projects.rows);
res.render('main', { title: 'My Projects', projects: projects.rows});
});
});
});
}
};
You need to familiarize yourself with asynchronous flow-control. It can be tricky because the async functions (postgres queries in this case) will execute right after another in the same turn of the event loop, while the results come trickling in in subsequent turns.
For your code example, this effectively means that i will be set to projects.rowCount-1 and project will be set to projects.rows[project.rowCount-1] almost instantly, while the queries have been queued up. They stay like this after the result for the queries come in. Not what you want.
The quickes solution is to use the Async library. https://github.com/caolan/async . This will handle the tedious bean-counting for you.
For this particular example, you'd replace the code within the client.connect callback with something like
addTasksToProject = function(projectRow, cb) { // called once for each project row
client.query("SELECT * FROM task WHERE project_id="+projectRow.id, function(err, result) {
if(err) return cb(err) // let Async know there was an error. Further processing will stop
projectRow.tasks = result.rows
cb(null) // no error, continue with next projectRow, if any
}
}
client.query("SELECT * FROM project", function(err, projects) {
if (err) return console.error(err)
async.each(projects.rows, addTasksToProject, function(err) {
if (err) return console.error(err)
// all project rows have been handled now
res.render('main', { title: 'My Projects', projects: project.rows});
})
}
Note that because how Javascript object references work, the objects part of the project.rows array will be actually modified in place. This wouldn't be the case if you'd actually try to assign a new value to the projectRow variable.

Resources