I need to GET all the data of a workbook, and I tried one method, but it does not work properly.. The problem is that the Promise is returning the first line of the first worksheet, but it does not continue the process for the rest of the rows of the worksheet, respectively, all the worksheets and I don't know what to do. Maybe you know..
So I wrote this code:
const SheetGet = {
getSheet: (req, res) => {
return new Promise ((resolve, reject) => {
XlsxPopulate.fromFileAsync(filePath)
.then(workbook => {
const wb = xlsx.readFile(filePath, {cellDates: true});
const sheetNames = wb.SheetNames;
sheetNames.forEach(function (element){
let endOfData = false;
let i = 2;
let dataArr = [];
while (endOfData === false){
let taskId = workbook.sheet(element).cell("A" + i.toString()).value();
if (taskId !== undefined){
res.send({
type: 'GET',
list_name: element,
task_id: taskId,
task_name: workbook.sheet(element).cell("B" + i.toString()).value(),
task_description: workbook.sheet(element).cell("C" + i.toString()).value(),
task_due_date: workbook.sheet(element).cell("D" + i.toString()).value(),
task_priority: workbook.sheet(element).cell("E" + i.toString()).value(),
task_status: workbook.sheet(element).cell("F" + i.toString()).value(),
task_notes: workbook.sheet(element).cell("G" + i.toString()).value()
});
i++;
}
else {
endOfData = true;
}
}
})
});
})
}
}
It only gets this an then it stops, and I need to get all of the data from the worksheet.
Do you have any idea on how to resolve this issue? Or the proper way to make it work? Thank you very very much for your time and help!!! Much appreciated every help!!
P.S. I tried this code with "console.log", and it works very well, but the problem is when I changed to res.send, in order to get the info to Postman.
I assume you are using express as the framework, the problem is when you use res.send method, the server already send the data to client, while the rest of the code still running in the background. What I'm gonna do with this case are like this.
const SheetGet = {
getSheet: (req, res) => {
return new Promise ((resolve, reject) => {
XlsxPopulate.fromFileAsync(filePath)
.then(workbook => {
const wb = xlsx.readFile(filePath, {cellDates: true});
const sheetNames = wb.SheetNames;
sheetNames.forEach(function (element){
let endOfData = false;
let i = 2;
let dataArr = [];
while (endOfData === false){
let taskId = workbook.sheet(element).cell("A" + i.toString()).value();
if (taskId !== undefined){
dataArr.push({ // this one
type: 'GET',
list_name: element,
task_id: taskId,
task_name: workbook.sheet(element).cell("B" + i.toString()).value(),
task_description: workbook.sheet(element).cell("C" + i.toString()).value(),
task_due_date: workbook.sheet(element).cell("D" + i.toString()).value(),
task_priority: workbook.sheet(element).cell("E" + i.toString()).value(),
task_status: workbook.sheet(element).cell("F" + i.toString()).value(),
task_notes: workbook.sheet(element).cell("G" + i.toString()).value()
});
i++;
}
else {
endOfData = true;
}
}
})
return res.json({ data: dataArr }); // this one
});
})
}
}
While there is some unnecessary code, the least change you can do to make it works are the code above.
Cheers.
Related
Hello everybody I have a problem with the Node JS function that I want it to return https get request final edited data, I know there are a lot of solutions for this async problem but I tried them all and still can't figure out what is wrong with my code?
here is my function without any other solutions editing:
function getMovie(apiKey, gen) {
const baseUrl = "https://api.themoviedb.org/3/discover/movie?api_key=" + apiKey + "&language=en-US&include_adult=false&include_video=false&page=1&with_genres=" + gen;
https.get(baseUrl, function (responce) {
console.log(responce.statusCode);
var d = "";
responce.on("data", function (data) {
d += data;
});
responce.on("end", () => {
const finalData = [];
const moviesData = JSON.parse(d);
const result = moviesData.results;
const maxx = result.length;
const rand = Math.floor(Math.random() * maxx);
const title = result[rand].title;
const rDate = result[rand].release_date;
const overview = result[rand].overview;
const imageRoot = result[rand].poster_path;
const movieId = result[rand].id;
const movieRating = result[rand].vote_average;
// here will push those variables to finalData array
// then return it
return finalData;
});
}).on('error', (e) => {
console.error(e);
});
}
and want after this finalData returns:
const finalResult = getMovie(apiKey, genre);
it always returns undefined, How can I fix this? please anyone ca help me with this problem
thanks in advance.
I solved this problem using promises using this code:
const rp = require('request-promise');
function getMovie(url) {
// returns a promise
return rp(url).then(body => {
// make the count be the resolved value of the promise
let responseJSON = JSON.parse(body);
return responseJSON.results.count;
});
}
getMovie(someURL).then(result => {
// use the result in here
console.log(`Got result = ${result}`);
}).catch(err => {
console.log('Got error from getMovie ', err);
});
So, i am trying to make a bot that pings my minecraft server and shows the players on it. I want to be able to start and stop it with "!" commands. I´ve got the main thing working but i dont really know how i can edit the embed every 10 secs or so. Im using discord.js. I thought about somehow calling the editing function every 10 seconds but i dont really see a function which i could call. Also the discord.js documentation doesnt help really much, because its mostly outdated, and many things changed, from what i could see. Also i should probably say that the codes pretty messy, so sorry for that. Here's my code so far:
const client = new Discord.Client()
const mcping = require('mc-ping-updated');
var server_players_num;
var server_players_name = [];
var server_players_max;
var server_version;
var embed;
var x = 0;
var fields = {};
//INSERT IP AND PORT BELOW
var serverip = "";
var serverport = 16400;
client.on('ready', () => {
console.log("Connected as " + client.user.tag)
})
bot_secret_token = ""
function serverping() {
mcping(serverip, serverport, function(err, res) {
if (err) {
// Some kind of error
console.error(err);
} else {
// Success!
console.log(res);
server_players_num = res.players.online;
console.log(server_players_num);
server_players_max = res.players.max;
if (server_players_num > 0) {
x = 0;
while (x < server_players_num) {
server_players_name.push(res.players.sample[x].name);
console.log(server_players_name[x]);
fields.name = "Spieler:";
if (x == 0) {
//fields.value = server_players_name[x];
fields.value = "[" + server_players_name[x] + "]" + "(https://mcuuid.net/?q=" + res.players.sample[x].id + ")";
} else if (x > 0) {
fields.value = fields.value + '\n' + server_players_name[x];
}
x++
}
};
}
}, 3000);
};
serverping();
client.on('message', async message => {
if (message.content === '!start') {
// inside a command, event listener, etc.
const exampleEmbed = new Discord.MessageEmbed()
.setColor('#d2ff00')
.setTitle('Minecraft Server Status')
.setThumbnail('https://i.ibb.co/hg8nG1s/HTL-PB.png')
.addField("Spieler online:", server_players_num + "/" + server_players_max, true)
.addFields(fields)
.setTimestamp()
embed = await message.channel.send(exampleEmbed);
await embed.edit(exampleEmbed);
}
});
client.login(bot_secret_token)```
Try using setInterval().
client.on('ready', () => {
console.log("Connected as " + client.user.tag)
setInterval(serverping, 10000); //10000ms = 10s
})
A piece of advice, if you want your bot to work asynchronously with other functions, a 10-second delay may be too fast. 1-2 minutes is enough for most occasions.
I have a cloud function which triggers on certain database write(onCreate), it works as expected but it also throws an error "Function returned undefined, expected Promise or value" though I am returning a promise.
Attaching the code snippet below. there are nested promises in it. is there a better way to handle nested promises, I already checked many posts for nested promises but not able to figure out a proper solution.
Thanks in Advance
exports.calculateAnswer = function(snap, context, dbPath,bucket) {
const answerKey = snap.val();
const incidentId = context.params.incidentId;
const matchId = context.params.match;
var globalIncidentPath = globalIncidentRootPath.replace('${match}', matchId);
globalIncidentPath = globalIncidentPath + incidentId + '/'
var pdPath = pdRootPath.replace('${match}', matchId);
pdPath = pdPath + incidentId
pdPath = pdPath + "/" + bucket
var incidentsPath = incidentsRootPath.replace('${match}', matchId);
var earningsNodePath = earningsNodeRootPath.replace('${match}', matchId);
let app = admin.app();
var globalData = null;
var globalData = null;
const globalPromise = app.database(dbPath).ref(globalIncidentPath).once('value').then(function(snapshot) {
globalData = snapshot.val();
console.log("globalData ",globalIncidentPath, "data ",globalData);
if(globalData) {
console.log("fetching pddata")
return app.database(dbPath).ref(pdPath).once('value')
}
else{
console.log("No global data found");
return true
}
}).then(function(pdSnashot){
const pdData = pdSnashot.val()
if(pdData) {
var promises = []
pdSnashot.forEach(function(childSnap){
console.log('key ',childSnap.key)
console.log('users count ',childSnap.numChildren())
childSnap.forEach(function(usersSnap){
const userId = usersSnap.key
const incidentProcessed = incidentsPath + userId + '/processed/' + incidentId
if (childSnap.key === answerKey) {
const earningUserIdEPath = earningsNodePath + userId
//const earningEPath = earningUserIdEPath + '/e/'
let gocashValue = globalData['v'];
const earningFetchPromise = app.database(dbPath).ref(earningUserIdEPath).once('value').then(function(snapshot1){
let snapDict = snapshot1.val();
var newGoCash = gocashValue
var newPDGoCash = gocashValue
if (snapDict){
let currentGoCash =snapDict['e'];
let currentPDCash = snapDict['pd']
if(currentGoCash) {
newGoCash = currentGoCash + gocashValue;
}
if(currentPDCash) {
newPDGoCash = currentPDCash + gocashValue;
}
}
const obj = Object()
obj["e"] = newGoCash
obj["pd"] = newPDGoCash
const earningPromise = app.database(dbPath).ref(earningUserIdEPath).update(obj)
const tempGlobal = globalData
tempGlobal["skip"] = false;
const processedPromise = app.database(dbPath).ref(incidentProcessed).set(tempGlobal)
return Promise.all([earningPromise,processedPromise])
});
promises.push(earningFetchPromise)
}
else{
const tempGlobal = globalData
tempGlobal["skip"] = true;
const processIncidentPromise = app.database(dbPath).ref(incidentProcessed).set(tempGlobal);
promises.push(processIncidentPromise)
}
})
})
return Promise.all(promises).then(value => {
console.log("Pd promises completed",value);
return true
})
}
else{
console.log("No Pd Data Found");
return true
}
})
.catch(function(error){
console.log('error in promise resolve',error)
})
console.log('global promise',globalPromise)
return Promise.all([globalPromise])
})
I would modify your code as follows. See the comments within the code.
var globalData = null;
const globalPromise = app
.database(dbPath)
.ref(globalIncidentPath)
.once('value')
.then(function(snapshot) {
globalData = snapshot.val();
console.log('globalData ', globalIncidentPath, 'data ', globalData);
if (globalData) {
console.log('fetching pddata');
return app
.database(dbPath)
.ref(pdPath)
.once('value');
} else {
console.log('No global data found');
// return true; Better to throw an error here
throw new Error('No global data found');
}
})
//The following 3 lines don't bring anything
//Moreover they are most probably the reason of your error as you don't return anything in this then()
//.then(function(pdSnashot){
// console.log("");
//})
.catch(function(error) {
console.log('error in promise resolve', error);
return true;
//Note that if you don't need the console.log you may ommit the entire catch since the platform will handle the error itself.
});
console.log('global promise', globalPromise);
//return Promise.all([globalPromise]); // There is no reason to use Promise.all() here since there is only one promise chain returned in globalPromise
return globalPromise;
I am porting an old ruby script over to use javascript setting the function as a cron instance so it will run on schedule. The function queries our mysql database and retrieves inventory information for our products and then sends requests to a trading partners api to update our inventory on their site.
Due to nodes a-synchronicity I am running into issues. We need to chunk requests into 1000 items per request, and we are sending 10k products. The issue is each request is just sending the last 1000 items each time. The for loop that is inside the while loop is moving forward before it finishes crafting the json request body. I tried creating anon setTimeout functions in the while loop to try and handle it, as well as creating an object with the request function and the variables to be passed and stuffing it into an array to iterate over once the while loop completes but I am getting the same result. Not sure whats the best way to handle it so that each requests gets the correct batch of items. I also need to wait 3 minutes between each request of 1000 items to not hit the request cap.
query.on('end',()=>{
connection.release();
writeArray = itemArray.slice(0),
alteredArray = [];
var csv = json2csv({data: writeArray,fields:fields}),
timestamp = new Date(Date.now());
timestamp = timestamp.getFullYear() + '-' +(timestamp.getMonth() + 1) + '-' + timestamp.getDate()+ ' '+timestamp.getHours() +':'+timestamp.getMinutes()+':'+timestamp.getSeconds();
let fpath = './public/assets/archives/opalEdiInventory-'+timestamp+'.csv';
while(itemArray.length > 0){
alteredArray = itemArray.splice(0,999);
for(let i = 0; i < alteredArray.length; i++){
jsonObjectArray.push({
sku: alteredArray[i]['sku'],
quantity: alteredArray[i]["quantity"],
overstockquantity: alteredArray[i]["osInv"],
warehouse: warehouse,
isdiscontinued: alteredArray[i]["disc"],
backorderdate: alteredArray[i]["etd"],
backorderavailability: alteredArray[i]["boq"]
});
}
var jsonObject = {
login: user,
password: password,
items: jsonObjectArray
};
postOptions.url = endpoint;
postOptions.body = JSON.stringify(jsonObject);
funcArray.push({func:function(postOptions){request(postOptions,(err,res,body)=>{if(err){console.error(err);throw err;}console.log(body);})},vars:postOptions});
jsonObjectArray.length = 0;
}
var mili = 180000;
for(let i = 0;i < funcArray.length; i++){
setTimeout(()=>{
var d = JSON.parse(funcArray[i]['vars'].body);
console.log(d);
console.log('request '+ i);
//funcArray[i]['func'](funcArray[i]['vars']);
}, mili * i);
}
});
});
You would need async/await or Promise to handle async actions in node js.
I am not sure if you have node version which supports Async/await so i have tried a promise based solution.
query.on('end', () => {
connection.release();
writeArray = itemArray.slice(0),
alteredArray = [];
var csv = json2csv({ data: writeArray, fields: fields }),
timestamp = new Date(Date.now());
timestamp = timestamp.getFullYear() + '-' + (timestamp.getMonth() + 1) + '-' + timestamp.getDate() + ' ' + timestamp.getHours() + ':' + timestamp.getMinutes() + ':' + timestamp.getSeconds();
let fpath = './public/assets/archives/opalEdiInventory-' + timestamp + '.csv';
var calls = chunk(itemArray, 1000)
.map(function(chunk) {
var renameditemsArray = chunk.map((item) => new renamedItem(item, warehouse));
var postOptions = {};
postOptions.url = endpoint;
postOptions.body = JSON.stringify({
login: user,
password: password,
items: renameditemsArray
});
return postOptions;
});
sequenceBatch(calls, makeRequest)
.then(function() {
console.log('done');
})
.catch(function(err) {
console.log('failed', err)
});
function sequenceBatch (calls, cb) {
var sequence = Promise.resolve();
var count = 1;
calls.forEach(function (callOptions) {
count++;
sequence = sequence.then(()=> {
return new Promise(function (resolve, reject){
setTimeout(function () {
try {
cb(callOptions);
resolve(`callsequence${count} done`);
}
catch(err) {
reject(`callsequence ${count} failed`);
}
}, 180000);
});
})
});
return sequence;
}
function makeRequest(postOptions) {
request(postOptions, (err, res, body) => {
if (err) {
console.error(err);
throw err;
}
console.log(body)
});
}
function chunk(arr, len) {
var chunks = [],
i = 0,
n = arr.length;
while (i < n) {
chunks.push(arr.slice(i, i += len));
}
return chunks;
}
function renamedItem(item, warehouse) {
this.sku = item['sku']
this.quantity = item["quantity"]
this.overstockquantity = item["osInv"]
this.warehouse = warehouse
this.isdiscontinued = item["disc"]
this.backorderdate = item["etd"]
this.backorderavailability= item["boq"]
}
});
Could you please try this snippet and let me know if it works?I couldn't test it since made it up on the fly. the core logic is in the sequenceBatch function. the The answer is based on an another question which explains how timeouts and promises works together.
Turns out this wasn't a closure or async issues at all, the request object I was building was using references to objects instead of shallow copies resulting in the data all being linked to the same object ref in the ending array.
I am getting stuck with trying to get JavaScript promise to work as intended.
My code:
var p = new Promise(function(resolve, reject) {
for (var i = 0; i < pics_needed.length; i++) {
download_pics(pics_needed[i])
}
for (var i = 0; i < partners_pics_needed.length; i++) {
partners_download_pics(partners_pics_needed[i])
}
resolve('Success!');
})
p.then(function() {
AsyncStorage.setItem("database",responseText)
AsyncStorage.removeItem("time")
alert ("Success! \nYour update has been installed.")
go()
});
Both functions that are called in the for loop download pictures from a server. The problem is, the p.then part of the function is running before all the pictures are downloaded. How can I alter this so that the p.then part happens after all the downloading is complete?
What the functions do:
function download_pics (id){
var path = RNFS.DocumentDirectoryPath + '/' + id + '.jpg';
fetch('address of server ='+id)
.then((response) => response.text())
.then((responseText) => {
var pic_object = JSON.parse(responseText)
RNFS.writeFile(path, pic_object.response, 'base64')
});
}
As hinted in the comments - promises are not worthless if you're going to go behind their backs.
function download_pics (id){
var path = RNFS.DocumentDirectoryPath + '/' + id + '.jpg';
return fetch('address of server ='+id) // <--- NOTE: return here
.then((response) => response.text())
.then((responseText) => {
var pic_object = JSON.parse(responseText)
return RNFS.writeFile(path, pic_object.response, 'base64') // <-- and here
});
}
and then
var pics_promises = pics_needed.map(function(pic) {
return download_pics(pic);
});
var partners_pics_promises = partners_pics_needed.map(function(pic) {
return partners_download_pics(pic);
});
return Promise.all(pics_promises.concat(partners_pics_promises));
EDIT: added the RNFS.writeFile to the promise chain per #adeneo (I'm not familiar with RNFS).