Promise to retrieve Timeline - node.js

Using Parse.com for few months now, I started to create some Cloud Function To let me create and retrieve some element in a TimeLine
I need to get my information from timeline's class and once I retrieve elements, I have to call getStat to add in the same object Widgets both information from my query and from the results from getStat.
I have tried to use Promise to achieve this, but not sure it was the best way to deal with it. Any suggestions / help ?
Parse.Cloud.define("getTimeline", function(request, response) {
var user = request.params.user;
var limit = request.params.limit;
var page = request.params.page;
if (limit === undefined) limit = 10;
if (page === undefined) page = 0;
var Timeline = Parse.Object.extend("timeline");
var query = new Parse.Query(Timeline);
query.equalTo("user", user);
query.descending('createdAt');
query.limit(limit);
query.skip(page * limit);
var Widgets = {};
query.find().then(function(results) {
var promise = Parse.Promise.as();
_.each(results, function(result) {
var Widget = new Object();
Widget.data = result;
var timeline_id = result.get('timeline_id');
promise = promise.then(function() {
return Parse.Cloud.run('getStats', {
'timeline_id': timeline_id
}).then(function(stat) {
Widget.stat = stat;
Widgets[timeline_id] = Widget;
});
});
});
return promise;
}).then(function() {
response.success(Widgets);
},
function(error) {
response.error("Error: " + error.code + " " + error.message);
});
});

Related

Getting empty array in nodejs

I am posting value But I am getting empty array . I know its node asynchronous problem . But I don't know how do i solve this. I have refer this following link:
How do I return the response from an asynchronous call?
But I could not able to understand . Kindly help me to understand promises and how do i use that in my code.
router.post('/inspection_list', function (req, res) {
var id = req.body.project_id;
console.log(id)
// res.send("ok")
db.inspection.findOne({'_id':id},(err,response)=>{
if(err){
console.log("error");
}
else{
console.log("Data")
var inspection = [];
var data = response.inspection_data;
var f = data.map(function (item) {
var fielduser = item.fielduser_id
db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)},(err,user)=>{
console.log(user.owner_name);
console.log(item.inspection_name)
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
})
});
console.log(inspection) // Here am getting empty value
// setTimeout(function(){ console.log(inspection) }, 5000); my timeout code
}
})
});
router.post('/inspection_list', async function (req, res) {
var id = req.body.project_id;
try{
var response = await db.inspection.findOne({'_id':id})
var inspection = [];
var data = response.inspection_data;
for ( var i = 0; i<data.length; i++){
var item = data[i]
var fielduser = item.fielduser_id
var user = await db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)})
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
}
}
catch(err){
throw err
}
})
This uses async and await, you can use it if you are using node version >=7.6
Also note the following:
router.post('/inspection_list', async function (req, res)
Handling each error seperately
router.post('/inspection_list', async function (req, res) {
var id = req.body.project_id;
try{
var response = await db.inspection.findOne({'_id':id})
}
catch(err){
// handle error here
throw err
}
var inspection = [];
var data = response.inspection_data;
for ( var i = 0; i<data.length; var item = data[i]
var fielduser = item.fielduser_id
try{
var user = await db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)})
}
catch(err){
// handle error
}
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
}
})
Using mongoose would be the easy way out, it returns Promises for all query and save functions, so you'd simply do:
YourModel.findOne({params}).then(() => {...})
If you're unable to do that, in your case, a 'promisified' example would be:
var findAndFillArray = (project_id) => new Promise((resolve) => {
.... your previous code here ....
inspection.push({inspection_name:item.inspection_name,field_user_name :
user.owner_name})
if (data.length === inspection.length){ // Or some other preferred condition
resolve(inspection);
}
})
Then you'd call this function after you get the id, like any other function:
var id = req.body.project_id;
findAndFillArray(id).then((inspection_array) => {
res.send(inspection_array) // Or whatever
})
Now, map and all list functions are synchronous in JS, are you sure the error is due to that?

nodejs async.parallel not working properly

I am unable to get proper output when trying to read data from redis and then send it out to user in json format.
This is my code
//API to get slot for a particular date range
app.get('/listcapacity/:ticketid/:fromdate/:todate', function(req, res) {
var id = req.params.ticketid;
var fromdate = req.params.fromdate;
var todate = req.params.todate;
var result = {};
var data_output = [];
var asyncTasks = [];
var currentDate = new Date(fromdate);
var between = [];
var end = new Date(todate);
while (currentDate <= end) {
var tempdate = new Date(currentDate).toISOString();
var dump = tempdate.toString().split("T");
between.push(dump[0]);
currentDate.setDate(currentDate.getDate() + 1);
}
between.forEach(function(entry) {
asyncTasks.push(function(callback) {
client.exists(id+entry, function (err, reply) {
if (reply === 1) {
console.log("Found");
client.get(id+entry, function (err, reply) {
var output = JSON.parse(reply);
data_output = data_output.concat(output);
});
}
callback();
});
});
});
async.parallel(asyncTasks, function(){
// All tasks are done now
result['data'] = data_output;
result['response'] = 1;
result['message'] = 'vacancies list fetched successfully!';
res.json(result);
});
});
I am always getting the output {"data":[],"response":1,"message":"vacancies list fetched successfully!"}
Even though I have checked that the keys are there in redis and it is always being Found by the application too.
For some reason the redis part is getting executed after the data has been sent to user. Why is this happening? I know redis works in async hence used the async.parallel function to take care of this but even then I endup with the same issue that I would have if I wouldnt have used async. What is the reason for this?
The client.get is an async operation and you have to callback in there. Also, you need an else statement and you need a callback in there as well:
//API to get slot for a particular date range
app.get('/listcapacity/:ticketid/:fromdate/:todate', function (req, res) {
var id = req.params.ticketid;
var fromdate = req.params.fromdate;
var todate = req.params.todate;
var result = {};
var data_output = [];
var asyncTasks = [];
var currentDate = new Date(fromdate);
var between = [];
var end = new Date(todate);
while (currentDate <= end) {
var tempdate = new Date(currentDate).toISOString();
var dump = tempdate.toString().split("T");
between.push(dump[0]);
currentDate.setDate(currentDate.getDate() + 1);
}
between.forEach(function (entry) {
asyncTasks.push(function (callback) {
client.exists(id + entry, function (err, reply) {
if (reply === 1) {
console.log("Found");
client.get(id + entry, function (err, reply) {
var output = JSON.parse(reply);
data_output = data_output.concat(output);
return callback();
});
} else {
return callback();
}
});
});
});
async.parallel(asyncTasks, function () {
// All tasks are done now
result['data'] = data_output;
result['response'] = 1;
result['message'] = 'vacancies list fetched successfully!';
res.json(result);
});
});

Update Arrays in node.js on disconnection in socket.io

I am trying to create a new socket.io real time analytic connection. I have two types of users. Normal users and their drivers.
Here is the code for authorization
io.configure(function()
{
io.set('authorization', function(handshake, callback)
{
var userId = handshakeData.query.userId;
var type = handshakeData.query.type;
var accessKey = handshakeData.query.accessKey;
var query = "";
if(type = '')
query = 'SELECT * FROM users WHERE id = ' + userId + ' AND accessKey = ' + accessKey;
else
query = 'SELECT * FROM drivers WHERE id = ' + userId + ' AND accessKey = ' + accessKey;
db.query(query)
.on('result', function(data)
{
if(data)
{
if(type == '')
{
var index = users.indexOf(userId);
if (index != -1)
{
users.push(userId)
}
}
else
{
var index = drivers.indexOf(userId);
if (index != -1)
{
drivers.push(userId)
}
}
}
else
{
socket.emit('failedAuthentication', "Unable to authenticate");
}
})
.on('end', function(){
socket.emit('failedAuthentication', "Unable to authenticate");
})
});
});
For disconnection i have this
socket.on('disconnect', function()
{
});
i want to remove the very userId i added on disconnect. How would i do that. can i append anything to socket or what should i do?
If you're just trying to remove the userId from your users and drivers arrays, you can do this:
socket.on('disconnect', function() {
// remove userId from users and drivers arrays
var index;
index = users.indexOf(userId);
if (index !== -1) {
users.splice(index, 1);
}
index = drivers.indexOf(userId);
if (index !== -1) {
drivers.splice(index, 1);
}
});
Or, you can DRY it up a bit:
function removeItem(array, item) {
var index = array.indexOf(item);
if (index !== -1) {
array.splice(index, 1);
}
}
socket.on('disconnect', function() {
removeItem(users, userId);
removeItem(drivers, userId);
});
This code assumes that you put this in the same closure where the userId variable is present. If you are not doing that, then you will probably need to put the userId as a property on the socket object so that it is accessible when you need it. You don't show the larger context of how your code is organized or where this event handler is located so we can't make a more specific recommendation without seeing that.

How to assign data for property of class after get data from Postgres

I have a problem when assign data from Postgres
this my snippet:
var database = function () {
client.connect(function(err) {
if(err) {
return console.error('could not connect to postgres', err);
}
});
};
database.prototype.getData = function() {
this.data = [];
this.queryStr = 'SELECT * FROM "agents"';
this.query = client.query(this.queryStr);
var data = [];
this.query.on('row', function(row) {
data.push(row);
//console.log(data); // get data successfully
});
//could not assign data
console.log(data); // but when go out above function, data become no value
this.data = data; // and then I can not assign it for property of class (like this.data)
};
Could anyone help me to resolve this.sorry my English. Tks alot.
Your data is assigned inside a callback which is executed after your method has run.
Usually you would pass a callback function when execution of your function is over.
I'm not skilled at using postgre library, but here's a pseudo-code:
database.prototype.getData = function(success) {
this.data = [];
this.queryStr = 'SELECT * FROM "agents"';
this.query = client.query(this.queryStr);
var self = this;
var data = [];
this.query.on('row', function(row) {
data.push(row);
//console.log(data); // get data successfully
});
this.query.on('end', function() { //when the query executes succesfully
self.data = data;
success(); //call success callback or perform other actions
});
};

Context in a bound node-mysql callback

I am defining a user object. If the user is logged in they have an ID of more than zero. Then
the conditional calls a node-mysql query and the results are assigned to the object properties. I have binded (bound?) the context in the node-mysql query callback to the "this" of the constructor(I think). My problem is when the user is not logged in and the ID is zero. The context is different. I know this because I copied the property assignments from the "else" part of the conditional into the "if" part and it worked. But I don't want to leave that because it would always query.
var Q = require("q");
var mysql = require('mysql');
function User(id, type) {
var deferred = Q.defer();
// If the user is logged in
if (id > 0) {
connection.query(query, function(err, results) {
if(err) {
deferred.reject(new Error(err))
} else {
var result = results[0];
this.id = result.id;
this.type = result.type;
this.nickname = result.nickname;
deferred.resolve(this);
}
}.bind(this));
} else {
this.id = 0;
this.type = 1;
this.nickname = "guest";
deferred.resolve(this);
}
return deferred.promise;
}
The object is instantiated here ... for example. The problem is when a user that is
not logged in (and has an ID of zero) is instantiated the object is empty, but otherwise
contains the properties.
var renderIndex = function(req, res) {
var localId = req.session.passport.user ? req.session.passport.user : 0,
options = {};
var user = new User(localId, 1);
return Q.all([
findGames(),
user
])
.then (function(allArray) {
var gamesObj = allArray[0],
userObj = allArray[1];
options.title = 'Title';
options.games = gamesObj;
options.user = userObj;
// Render the index jade template
res.render('index', options);
})
.done();
};

Resources