How can i access nested promise data? - node.js

I am trying to set up a route that sends data from a nested promise to my vue app.
But i'm having trouble with the getting data from the nested promises.
i tried using a callback with no success
app.get('/notification', (req, res) => {
const getData = (data) => {
console.log(data)
}
scheduler(data)
})
const scheduler = (callback) => {
sftp
.connect({ credentials })
.then(() => {
return sftp.list(root);
})
.then(async data =>
{
const filteredFile = data.filter(file => {
let currentDate = moment();
let CurrentTimeMinusFive = moment().subtract(5, "minutes");
let allAccessTimes = file.accessTime;
let parsedAccessTimes = moment(allAccessTimes);
let filteredTime = moment(parsedAccessTimes).isBetween(
CurrentTimeMinusFive,
currentDate
);
return filteredTime;
});
for (const file of filteredFile) {
let name = file.name;
let filteredThing;
await sftp
.get(`Inbound/${name}`)
.then(data => {
csv()
.fromString(data.toString())
.subscribe(function (jsonObj) {
return new Promise(function (resolve, reject) {
filteredThing = new Notification(jsonObj);
filteredThing.save()
.then(result => {
console.log(result);
callback(result) **// THIS IS THE RESULT I NEED IN MY FRONT END**
})
.catch(err => {
console.log(err);
});
resolve();
});
});
});
}
})
When i go to localhost/notification i get:
ReferenceError: data is not defined
Thanks in advance!

Related

In node.js, why is my data not getting passed back after a asynchronous file read using a Promise

I know for sure that my pullData module is getting the data back from the file read but the function calling it, though it has an await, is not getting the data.
This is the module (./initialise.js) that reads the data:
const fs = require('fs');
const getData = () => {
return new Promise((resolve, reject) => {
fs.readFile('./Sybernika.txt',
{ encoding: 'utf8', flag: 'r' },
function (err, data) {
if (err)
reject(err);
else
resolve(data);
});
});
};
module.exports = {getData};
And this is where it gets called (app.js):
const init = require('./initialise');
const pullData = async () => {
init.getData().then((data) => {
return data;
}).catch((err) => {
console.log(err);
});
};
const start = async() => {
let data = await pullData();
console.log(data);
}
start();
putting 'console.log(data)' just before return(data) in the resolve part of the call shows the data so I know it's being read OK. However, that final console.log shows my data variabkle as being undefined.
Any suggestions?
It's either
const pullData = async () => {
return init.getData().then((data) => {
return data;
}).catch((err) => {
console.log(err);
});
};
or
const pullData = async () =>
init.getData().then((data) => {
return data;
}).catch((err) => {
console.log(err);
});
Both versions make sure a promise returned by then/catch is passed down to the caller.

How do I access the data array in my axios function

I'm trying to access the data array that has the information from the request, but I cannot seem to figure it out.
When I try to display it in my view, I get an undefined cannot read property of length;
const getData = () => {
axios.get("https://www.worldometers.info/coronavirus/")
.then(res => {
const data = [];
const $ = cheerio.load(res.data);
$('.maincounter-number').each((index, element) => {
const numberData = $(element).text();
data[0] = {numberData: numberData};
});
}).catch(err => {
console.log("Error fetching and parsing data: ", err);
});
}
app.get("/", (req, res) => {
const data = getData();;
res.render('index', {title: 'Home', data: data});
});
Pug View
p #{data.dataNumbers}
I've also tried this function as well but I get the same issue
async function scrapeWorldOMeter(){
try{
const worldOMeterResponse = await axios.get("https://www.worldometers.info/coronavirus/");
const data = [];
const $ = cheerio.load(worldOMeterResponse.data);
$('.maincounter-number').each((index, element) => {
const numberData = $(element).text();
data[0] = {numberData: numberData};
return data[0];
});
}
catch(err){
throw new Error(`Can't scrape WorldOMeter ${err}`)
}
}
app.get("/", async(req, res) => {
const data = await scrapeWorldOMeter()
res.render('index', {title: 'Home', data});
});
You can fix your first code snippet by using promises properly,
const getData = () => {
return axios
.get('https://www.worldometers.info/coronavirus/')
.then((res) => {
const data = [];
const $ = cheerio.load(res.data);
$('.maincounter-number').each((index, element) => {
const numberData = $(element).text();
data[0] = { numberData: numberData };
});
return data[0];
})
.catch((err) => {
console.log('Error fetching and parsing data: ', err);
});
};
app.get('/', (req, res) => {
const data = getData().then((res) => {
res.render('index', { title: 'Home', data: data });
});
});
The problem here was that you were not returning the axios promise in getData() and also you were not chaining the response with then in the get route.
Your second code snippet can be fixed by using async/await properly,
async function scrapeWorldOMeter() {
try {
const worldOMeterResponse = await axios.get(
'https://www.worldometers.info/coronavirus/'
);
const data = [];
const $ = cheerio.load(worldOMeterResponse.data);
$('.maincounter-number').each((index, element) => {
const numberData = $(element).text();
data[0] = { numberData: numberData };
});
return data[0];
} catch (err) {
throw new Error(`Can't scrape WorldOMeter ${err}`);
}
}
app.get("/", async(req, res) => {
const data = await scrapeWorldOMeter();
res.render('index', {title: 'Home', data});
});
The problem here was that you were returning data[0] inside the jquery each loop. You simply have to move it to the next line outside the loop

Empty array after calling the function that fills the array

I am trying to get the array after it is filled in a function but it is empty when I print it out.
Code:
var usersList = [];
app.post('/submitLogin',function(req,res) {
getUsersGroups();
console.log(usersList);
});
function getUsersGroups() {
const users = new Promise((resolve, reject) => {
dbConnection
.getUsers()
.then(data => {
resolve(data)
})
});
const groups = new Promise((resolve, reject) => {
dbConnection
.getGroups()
.then(data => {
resolve(data)
})
});
Promise.all([users, groups])
.then(data => {
usersList = data[0];
groupsList = data[1];
console.log(usersList)
});
}
However, the console.log in the getUsersGroups(), prints out the filled array but it is empty in the app.post('/submitLogin...')
Why is this happening assuming that getUsersGroups() runs before I try to print out the array?
You are not observing the async execution of your db call.
The console.log(usersList); happens BEFORE the db call, so it is empty.
You must adapt your code like this and post the code AFTER the db execution:
app.post('/submitLogin', function (req, res) {
getUsersGroups().then((data) => {
console.log(data)
res.send(data.usersList)
})
})
function getUsersGroups () {
const users = new Promise((resolve, reject) => {
dbConnection
.getUsers()
.then(data => {
resolve(data)
})
})
const groups = new Promise((resolve, reject) => {
dbConnection
.getGroups()
.then(data => {
resolve(data)
})
})
return Promise.all([users, groups])
.then(data => {
console.log(data[0])
return {
usersList: data[0],
groupsList: data[1]
}
})
}
I strongly suggest to don't change a global variable like usersList (that I removed from my example)
because if you receive two request contemporaneously, the second one could overwrite the data of the first one and
cause many side effect.
app.post('/submitLogin', async function(req,res) {
await getUsersGroups();
console.log(usersList);
});
try this

Cloudinary async wait upload for multiple images at once then save to array in node js

Hi I am look for a solution for API server side upload using Node Js asyc wait functionality for uploading multiple images then catch into an array. I follow this link to implement my code. In console it shows the array that I expect, but it does not give me any responses.
Here is what I tried so far,
exports.upload_image = async(req, res) =>{
//let filePaths = req.files.path;
let multipleUpload = new Promise(async (resolve, reject) => {
let upload_len = req.files.length;
let upload_res = new Array();
for(let i = 0; i < upload_len; i++)
{
let filePath = req.files[i].path;
await cloudinary.v2.uploader.upload(filePath, { use_filename: true, unique_filename: false }, function (error, result) {
if(upload_res.length === upload_len)
{
/* resolve promise after upload is complete */
resolve(upload_res)
}
else if(result)
{
/*push public_ids in an array */
upload_res.push(result.public_id);
} else if(error) {
console.log(error)
reject(error)
}
})
}
})
.then((result) => result)
.catch((error) => error)
let upload = await multipleUpload;
res.json({'response':upload})
}
Any suggestion would be appreciated. Thanks.
I would take a different approach here. You are mixing up promises and async/await in a way that is pretty hard to read and debug.
I would do this instead:
Map your files to an array of promises and then call Promise.all():
exports.upload_image = async(req, res) =>{
// res_promises will be an array of promises
let res_promises = req.files.map(file => new Promise((resolve, reject) => {
cloudinary.v2.uploader.upload(file.path, { use_filename: true, unique_filename: false }, function (error, result) {
if(error) reject(error)
else resolve(result.public_id)
})
})
)
// Promise.all will fire when all promises are resolved
Promise.all(res_promises)
.then(result => res.json({'response':upload}))
.catch((error) => {/* handle error */ })
}
Here's a snippet with a fake upload function and a list of 'files':
function upload(file, fn) {
// fake upload file, just return file as id
setTimeout(() => fn(null, {
public_id: file
}), Math.floor(Math.random() * 500))
}
// fake req.files
let files = [1, 2, 3, 4, 5, 6]
let upload_image = () => {
let upload_res = files.map(file => new Promise((resolve, reject) => {
upload(file, (error, result) => {
if (error) reject(error)
else resolve(result.public_id);
})
}))
Promise.all(upload_res)
.then(result => console.log({
'response': result
}))
.catch(error => error)
}
upload_image()

Async Await Node js

I am learning async await using node js
var testasync = async () =>
{
const result1 = await returnone();
return result1;
}
testasync().then((name)=>{
console.log(name);
}).catch((e) =>{
console.log(e);
});
var returnone = () =>{
return new Promise((resolve,reject)=>
{
setTimeout(()=>{
resolve('1');
},2000)
})
}
It fails with returnone is not a function. What am i doing wrong? calling the function just by itself work
returnone().then((name1) => {
console.log(name1)
})
Just calling the above code works
The reason you are getting this error because of hoisting. Your code seen by JS would look like this
var returnone;
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
returnone = () => {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
So the value of returnone is undefined.
You are assigning the function to the variable returnone at the end of the code, but you are trying to call that function before this assignment. You have two options to fix the code:
Option 1
Use a function declaration; this way, the function is hoisted and you can use it right from the start:
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});
function returnone() {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
Option 2
Assign the function to the variable before you try to call it:
var returnone = () => {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve('1');
}, 2000)
})
}
var testasync = async () => {
const result1 = await returnone();
return result1;
}
testasync().then((name) => {
console.log(name);
}).catch((e) => {
console.log(e);
});

Resources