Hi i can't get my push function to work..
my code
var result = {};
dpd.timesheetsdone.get(function (timesheets, err) {
if(err) return console.log(err);
timesheets.forEach(function(entry, index) {
result[entry.timesheets[0].week] = [];
result[entry.timesheets[0].week].push(entry);
//heres my push
}
);
setResult(result);
});
When runing it dosent push my entry, it just does like = and set result to 1 item, it dosen't push.
What could be the problem here ?
example of timesheets
http://pastebin.com/w2i7xYgm
The problem is here:
result[entry.timesheets[0].week] = [];
If you've ever put anything there before, that wipes it out; so you only ever see the last thing for that week.
You only want to do that assignment if you haven't already done it:
if (!result[entry.timesheets[0].week]) {
result[entry.timesheets[0].week] = [];
}
E.g.:
var result = {};
dpd.timesheetsdone.get(function(timesheets, err) {
if (err) return console.log(err);
timesheets.forEach(function(entry, index) {
if (!result[entry.timesheets[0].week]) {
result[entry.timesheets[0].week] = [];
}
result[entry.timesheets[0].week].push(entry);
});
setResult(result);
});
Or to avoid repeated object lookups:
var result = {};
dpd.timesheetsdone.get(function(timesheets, err) {
if (err) return console.log(err);
timesheets.forEach(function(entry, index) {
var week = entry.timesheets[0].week;
var weekArray = result[week];
if (!weekArray) {
weekArray = result[week] = [];
}
weekArray.push(entry);
});
setResult(result);
});
Related
I am trying to read some data from 2 different tables and parse a CSV file before rendering an ejs file.
I can get the data from both tables and from the CSV file but I seem to be unable to return the result.
Pretty sure this is a problem with the way I handle async execution but I fail to see what I am doing wrong.
I've spent the last 2 days reading about this (including the threads around here) and browsing but somehow the answer still escapes me.
First file - usercms.js
app.get('/userscms', function(req, res)
{
existingUsers.getExistingUsers()
.then(function(appUsers)
{
//global users array
//I can display these in my ejs file
globalAppUsers = appUsers;
})
.then(existingUsersAttributesQlik.getExistingUsersAttributesQlik())
.then(function(usersQlikAttributes)
{
//global user attributes array
//undefined data
globalUsersQlikAttributes = usersQlikAttributes;
})
.then(existingSuppliers.parseSuppliersCSV())
.then(function(supplierData)
{
//the result I am expecting
//this prints undefined
console.log(supplierData);
}).then(function()
{
res.render('userscms.ejs',
{
users: globalAppUsers,
attributes: globalUsersQlikAttributes
});
});
});
Second function - getxistingUsers.js (identical to the getExistingUsersAttributesQlik, except for the query)
var userData = [];
var appUsers = [];
(function (exports)
{
exports.getExistingUsers = function ()
{
return promisemysql.createConnection(dbconfig.development).then(function(conn)
{
var result = conn.query("SELECT id, username, firstName, lastName, email, phone, lastLogin, isAdmin, isValid, isPhoneValid, accountCreationDateTime FROM Users");
conn.end();
return result;
}).then(function(rows)
{
return rows;
}).then(function(rows)
{
if (rows.length)
{
userData = [];
appUsers = [];
rows.forEach(function (elem)
{
userData.push(_.toArray(elem));
});
for (i = 0; i < userData.length; i++)
{
var appUser = new appUserModel.AppUser(
userData[i][0],
userData[i][1],
userData[i][2],
userData[i][3],
userData[i][4],
userData[i][5],
userData[i][6],
userData[i][7],
userData[i][8],
userData[i][9],
userData[i][10]);
appUsers.push(_.toArray(appUser));
}
return appUsers;
}
else
{
console.log("NOPE");
return null;
}
}).then(function(appUsers)
{
console.log(appUsers);
return appUsers;
});
};
})(typeof exports === 'undefined' ? this['getExistingUsers'] = {} : exports);
Third file - parseSuppliersCSV.js
var supplierData = [];
var suppliersData = [];
var csvCount = 0;
(function (exports)
{
exports.parseSuppliersCSV = function ()
{
return new Promise(function(resolve, reject)
{
var fileStream = fs.createReadStream("myCSV.csv");
var parser = fastCsv();
csvCount = 0;
supplierData = [];
suppliersData = [];
fileStream
.on("readable", function ()
{
var data;
while ((data = fileStream.read()) !== null)
{
parser.write(data);
}
})
.on("end", function ()
{
parser.end();
});
parser
.on("readable", function ()
{
var data;
while ((data = parser.read()) !== null)
{
if(csvCount >= 1)
{
csvCount++;
var arrayOfStrings = data[0].split(';');
var supplier = new supplierModel.Supplier(arrayOfStrings[0],arrayOfStrings[1]);
suppliersData.push(_.toArray(supplier));
}
else
{
csvCount++;
}
}
})
.on("end", function ()
{
console.log("done");
//all OK here
console.log(suppliersData);
//this doesn't seem to return anything
return suppliersData;
});
});
};
})(typeof exports === 'undefined' ? this['parseSuppliersCSV'] = {} : exports);
Any ideas what I am doing wrong? Am I approaching this the wrong way?
I'll take a guess here and assume the promise you created should resolve to something...instead of returning a value.
.on("end", function ()
{
console.log("done");
//all OK here
console.log(suppliersData);
//this doesn't seem to return anything
return resolve(suppliersData);
});
On my Node JS backend I run this method.
var locations = [];
exports.constructionsiteParser = function constructionsiteParser(response){
var timestamp = new Date().toDateInputValue();
const $ = cheerio.load(response);
$('situation').each( function(){
var situation = [];
$(this).find('situationRecord').each( function(i){
var startLocationCode = $(this).find('alertCMethod2SecondaryPointLocation').find('specificLocation').text();
var endLocationCode = $(this).find('alertCMethod2PrimaryPointLocation').find('specificLocation').text();
var overallStartTime = $(this).find('overallStartTime').text();
var overallEndTime = $(this).find('overallEndTime').text();
if((startLocationCode != '') && new Date(timestamp) >= new Date(overallStartTime) && new Date(timestamp) <= new Date(overallEndTime) ){
Promise.all([
locationCodeToGeodataRequst.geodataByLocationcode(startLocationCode),
locationCodeToGeodataRequst.geodataByLocationcode(endLocationCode)
]).then( values =>{
return createSituationRecord($, this, startLocationCode, endLocationCode, values[0], values[1]);
}).then( function(obj){
console.log("before push", situation);
situation.push(obj);
console.log("after push", situation);
return situation;
}, handleError);
}
})
console.log("from outter", situation.length);
if(situation.length > 0){ //if situation is not empty
locations.push(situation);
}
})
console.log(locations);
}
The console.log("from outter", situation.length); at the bottom prints always 0
also the console.log(locations) is empty
This is a part of the log:
...
from outter 0
from outter 0
from outter 0
from outter 0
from outter 0
[]
before push []
after push [....
I think this happens because the node server runs the bottom part before the inner each loop finishes. So I want to make it more snychronized. What I want to do is something like:
outer each{
//run this first
inner each{
.....
}
//if inner each is done run this
if(...){}
}
But I don't know how to put this in the correct syntax.
I have tried it with nested Promises but it doesn't work.
you can return this promise. deal it at caller
You can make use of async.eachOf(). I took a different approach in making your code synchronous. Hope it helps you.
'use strict';
let locations = [];
exports.constructionsiteParser = function constructionsiteParser(response) {
const $ = cheerio.load(response);
$('situation').each(function () {
let situation = [];
async.eachOf($(this).find('situationRecord'), function (value, key, callback) {
innerLoop(callback);
}, function (err, situation) {
if (err) {
return console.error(err.message);
}
console.log("from outter", situation.length);
// this will run only if the inner loops completes
if (situation.length > 0) { //if situation is not empty
locations.push(situation);
}
});
});
console.log(locations);
};
function innerLoop(callback) {
let startLocationCode = $(this).find('alertCMethod2SecondaryPointLocation').find('specificLocation').text();
let endLocationCode = $(this).find('alertCMethod2PrimaryPointLocation').find('specificLocation').text();
let overallStartTime = $(this).find('overallStartTime').text();
let overallEndTime = $(this).find('overallEndTime').text();
if (isInvalid(startLocationCode, overallStartTime, overallEndTime)) {
return callback('some error msg');
}
Promise.all([
locationCodeToGeodataRequst.geodataByLocationcode(startLocationCode),
locationCodeToGeodataRequst.geodataByLocationcode(endLocationCode)
]).then(values => {
return createSituationRecord($, this, startLocationCode, endLocationCode, values[0], values[1]);
}).then((obj) => {
return callback(null, obj);
}).catch((err) => {
console.log('err', err.stack);
return callback(err);
});
}
function isInvalid(startLocationCode, startTime, endTime) {
let timestamp = new Date().toDateInputValue();
let isEmptyCode = startLocationCode === '';
let isYetToStart = new Date(timestamp) < new Date(startTime);
let isOver = new Date(timestamp) > new Date(endTime);
return isEmptyCode || isYetToStart || isOver;
}
You should take a deeper look into promises because they are the way to go for synchronous operations. Maybe try to merge your code into functions.
In getNestedFlags I'm adding values to finalJson array.
Then after console.log I can see entire finalJson array with values but resolve returns an empty array. Do you know how to achive the same result in resolve as in console.log?
getScheduledFlags: (idTc, idScheduled) => {
return new Promise((resolve, reject) => {
var getNestedFlags = (array1, array2, res) => {
array1.forEach(item => {
var childrenItems = res.filter(item1 => item1.id_parent == item.id)
if(childrenItems.length > 1){
var childrens = []
getNestedFlags(childrenItems, childrens, res)
array2[item.name] = childrens
} else {
array2[item.name] = item.value
}
})
}
_tc.get(idTc).then(result => {
var flags = result.flags
var bases = result.bases
_featureFlags.getAll().then(allFlags => {
tcScheduled= _featureFlags.getFinalTcFlags(result)
res = _this.replaceFlags(allFlags, tcScheduled.flags)
parentFlags = res.filter(item => item.id_parent == 0)
var finalJson = []
getNestedFlags(parentFlags, finalJson, res)
console.log(finalJson)
resolve(finalJson)
})
})
})
},
The code which you have posted must work as array is passed by reference rather than value in javascript. Check both the console.log() in the code before and after the call to resolve() function.
var finalJson = []
var parentFlags ='';
var res ='';
getNestedFlags(parentFlags, finalJson, res);
console.log(finalJson);
resolve(finalJson);
console.log(finalJson);
function getNestedFlags(parentFlags, finalJson, res){
finalJson.push(1);
finalJson.push(2);
finalJson.push(3);
}
function resolve(finalJson){
finalJson.push(4);
finalJson.push(5);
}
Initializing array by [] was my problem.
Now with {} everything is fine.
I am trying to use the values given by class 1 to find more values in class 2 related to class 1's values. I was going to do this by looping the value of k, however, it seem no matter where I put the loop, it only uses the final value of k. Can anyone tell me how to deal with a necessity for indices when dealing with promises? I am new to both promises and parse. Edit: IF bracket was misplaced.
var Class1 = Parse.Object.extend("Class1");
var Class2 = Parse.Object.extend("Class2");
Parse.Promise.as().then(function () {
var query = new Parse.Query(Class1);
return query.find()
}).then(function (class1IDs) {
for (var k = 0; k < class1IDs.length; k++) {
var class1IDEntry = class1IDs[k];
var class1ID = class1IDEntry.id;
Parse.Promise.as().then(function () {
var class1 = new Class1();
class1.id = class1ID;
var query = new Parse.Query(Class2); //
query.equalTo("class1", class1);
return query.find()
}).then(function (class2IDs) {
var stuff;
});
}
}).then(function() {
done();
}, function(error) {
console.log(error);
done(new Error(error));
});
});
you want to wait for all the promises created inside the for loop to finish, before the done() call right - should the queries inside the loop run in series or parallel? The other issue you have is due to asynchronous nature of the code, all class1.id = class1ID will have class1ID of the last item in class1IDs (as you suspect)
Run through class1IDs in series
var Class1 = Parse.Object.extend("Class1");
var Class2 = Parse.Object.extend("Class2");
Parse.Promise.as().then(function() {
var query = new Parse.Query(Class1);
return query.find()
}).then(function(class1IDs) {
return class1IDs.reduce(function(promise, class1IDEntry) {
var class1ID = class1IDEntry.id;
var class1 = new Class1();
class1.id = class1ID;
var query = new Parse.Query(Class2); //
query.equalTo("class1", class1);
return promise.then(function() {
return query.find();
}).then(function(class2IDs) {
var stuff;
});
}, Parse.Promise.as());
}).then(function() {
done();
}, function(error) {
console.log(error);
done(new Error(error));
});
Run through class1IDs in parallel
var Class1 = Parse.Object.extend("Class1");
var Class2 = Parse.Object.extend("Class2");
Parse.Promise.as().then(function() {
var query = new Parse.Query(Class1);
return query.find()
}).then(function(class1IDs) {
return Parse.Promise.when.apply(null, class1IDs.map(function(class1IDEntry) {
var class1ID = class1IDEntry.id;
var class1 = new Class1();
class1.id = class1ID;
var query = new Parse.Query(Class2); //
query.equalTo("class1", class1);
return query.find()
.then(function(class2IDs) {
var stuff;
});
}));
}).then(function() {
done();
}, function(error) {
console.log(error);
done(new Error(error));
});
I am trying to return the value of itemInfo[0] from within this nested function. Can anyone help how I should return this value with a callback ?
function findItem(item) {
var itemInfo = [];
Item.findItem(item, function(err, itemInfo){
itemInfo[0].info = _.unescape(itemInfo[0].info);
itemInfo[0].title = _.unescape(itemInfo[0].title);
// console.log(itemInfo[0]);
return itemInfo[0];
});
};
Set the cb argument to null after you use it and check for its validity before calling.
function findItem(item, cb) {
var itemInfo = [];
Item.findItem(item, function(err, itemInfo){
if (cb) {
itemInfo[0].info = _.unescape(itemInfo[0].info);
itemInfo[0].title = _.unescape(itemInfo[0].title);
// console.log(itemInfo[0]);
cb( itemInfo[0] );
cb = null;
}
});
};
What if you returned the returned value?
function findItem(item) {
var itemInfo = [];
return Item.findItem(item, function(err, itemInfo){
itemInfo[0].info = _.unescape(itemInfo[0].info);
itemInfo[0].title = _.unescape(itemInfo[0].title);
// console.log(itemInfo[0]);
return itemInfo[0];
});
};