Getting an error with the "map" part when I try and run it Cannot read property 'map' of undefined"
The customers const is declared above so not sure. Where is the undefined is coming from? Does the map need declaring?
const AWS = require('aws-sdk'),
ses = new AWS.SES(),
fetch = require('node-fetch');
exports.handler = async (event) => {
console.log(event.customer_id);
const customers = await getCustomers();
customers.map(async customer => await sendEmailToCustomer(customer));
const customersEmailsPromises = customers.map(async customer => await sendEmailToCustomer(customer));
}
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
return json;
}
catch(e) {
throw e;
}
}
const sendEmailToCustomer = (customer) => new Promise((resolve, reject) => {
ses.sendEmail({
Destination:
{ ToAddresses: [customer.email] },
Message:
{
Body: { Text: { Data: `Your contact option is ${customer.customer_id}` } },
Subject: { Data: "Your Contact Preference" }
},
Source: "sales#example.com"
}, (error, result => {
if (error) return reject(error);
resolve(result);
console.log(result);
})
);
})
getCustomers doesn't return anything which means that customers is set to undefined.
Try this:
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
return json;
}
catch(e) {
throw e;
}
}
You also have to return something from the function that you pass as a parameter to .map
customers.map(async customer => {
return await sendEmailToCustomer(customer);
});
or just:
customers.map(async customer => await sendEmailToCustomer(customer));
And since .map returns a new array (does not mutate the original array), you'll have to store the return value:
const customersEmailsPromises = customers.map(async customer => await sendEmailToCustomer(customer));
Related
I have created a page that loads some data from api and I want to throw an error from the promise all if the api returns no data. How can this be done?
export const fruitsColor = async () : Promise => {
const response = await fetch(`....`);
if(!response.ok){
throw new Error('Error happened')
}
const data = await response.json();
return data;
};
export const fruitsType = async (): Promise => {
const response = await fetch(`....`);
if(!response.ok){
throw new Error('Error happened')
}
const data = await response.json();
return data;
};
export const getFruitsData = async (): Promise => {
return await Promise.all([
fruitsColor,
fruitsType,
])
.then(values => {
const results: FruitsStoreType = {
color: values[0],
type: values[1],
};
return results;
})
.catch(() => ({
color: [],
type: [],
}));
};
I think you have to pass Promise.all([fruitsColor(), fruitsType()]
Promise.all expects Promises and you are passing functions' references.
So, try to add the () to both the functions.
In this way the promise.all will catch the error
throw an error there to reach your goal
export const fruitsColor = async (): Promise<any> => {
const response = await fetch(`....`);
if (!response.ok) {
throw new Error('Error happened');
}
const data = await response.json();
return data;
};
export const fruitsType = async (): Promise<any> => {
const response = await fetch(`....`);
if (!response.ok) {
throw new Error('Error happened');
}
const data = await response.json();
return data;
};
export const getFruitsData = async (): Promise<any> => {
return await Promise.all([fruitsColor(), fruitsType()])
.then((values) => {
const results: FruitsStoreType = {
color: values[0],
type: values[1],
};
return results;
})
.catch(() => {
throw new Error('my own error');
});
};
I have a function that fetches data from an API, and the function works correctly as intended:
const getStockData = async (stock) => {
try {
const response = await axios.get(`${BASE_URL}${stock}${KEY_URL}`);
console.log(response);
return response;
} catch (error) {
console.error('Error', error.message);
}
};
And I have another function that gets data from my firebase which then passes in the .ticker into the function above however when I log the response from the promise the data is returned null
Is there a reason why its not working as intended?
const getMyStocks = async () => {
let promises = [];
let tempData = [];
const querySnapshot = await getDocs(collection(db, 'myStocks'));
querySnapshot.forEach((doc) => {
console.log(doc.data().ticker);
promises.push(
getStockData(doc.data().ticker).then((res) => {
console.log(res);
tempData = {
id: doc.id,
data: doc.data(),
info: res.data,
};
})
);
getMyStocks must return the resolution of the promises it creates...
// to reduce nested promises, this takes an FB doc and adds the getStockData query to it
const getFBAndTickerData = async doc => {
return getStockData(doc.data().ticker).then(res => {
console.log(res);
return {
id: doc.id,
data: doc.data(),
info: res.data,
};
});
}
const getMyStocks = async () => {
const querySnapshot = await getDocs(collection(db, 'myStocks'));
let promises = querySnapshot.docs.map(doc => {
console.log(doc.data().ticker);
return getFBAndTickerData(doc);
});
return Promise.all(promises);
}
I would like to return an object from the the async / await function A to pass it to another function.
Currently what I get as a result is Promise{ <pending> }' or undefined.
function A:
const parseRss = data => data.forEach(rssLink => {
const getFeed = async () => {
try {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: []
}
}
feed.items.forEach(item => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`)
});
return emailContent;
} catch (e) {
console.error(e);
}
};
return (async () => {
return await getFeed();
})();
});
Function B:
try {
const data = await getDataWithRss();
const emailData = await parseRss([{rss:'http://reddit.com/.rss'}]); // emailData is undefined
return formatEmail(emailData);
} catch (error) {
console.log(error);
}
How do I return emailContent from function A to use it in function B?
Thanks!
Since you made getFeed as async, no need another async. You are looping through, so return an array of promises. Once the you call use Promise.all to resolve. Since there could be multiple urls to fetch.
const parseRss = (data) =>
data.map((rssLink) => {
const getFeed = async () => {
try {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: [],
},
};
feed.items.forEach((item) => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`);
});
return emailContent;
} catch (e) {
console.error(e);
}
};
return getFeed();
});
try {
const data = await getDataWithRss();
const emailData = await Promise.all(parseRss([{rss:'http://reddit.com/.rss'}])); // emailData is undefined
return formatEmail(emailData);
} catch (error) {
console.log(error);
}
await will not work inside a forEach loop. Use a for...in loop instead.
actually, getFeed() is not necessary inside inner scope, you can use async in map callback:
const parseRss = data => data.map(async rssLink => {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: []
}
};
feed.items.forEach(item => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`)
});
return emailContent;
});
I have an async function that returns a value
async getUsername(env:string,skuName: string,token:string): Promise<any> {
let value = await this.getDeviceName(env,skuName,token);
return value;
};
in another function, I am calling this get username function like this
let productN;
const prod = this.getUsername(env,skuName,token).then((resp) => {
productN= resp;
this.wait(300);
});
the variable productN is working, as i am able to see the response in my log, but when i try to use productN outside of this block, i am running into undefined.
promotion = {
name: productN,
startDate: start,
endDate: end
};
I am trying to set name to productN, and i just can not get it to work.
Can anyone explain to me what i am doing wrong please? Thanks
You can either assign to the promotion when you receive the response -
const prod = this.getUsername(env,skuName,token).then((resp) => {
productN = resp;
promotion.name = resp
this.wait(300);
});
Since your getUsername is asynchronous, you can wait for the response using await and then assign to promotion object.
(async() => {
const resp = await this.getUsername(env,skuName,token);
promotion = {
name: resp,
startDate: start,
endDate: end
}
})();
--- Edit ---
const input = [
{
env: 'lorem',
skuname: 'skuname1',
token: 'dummy'
},
{
env: 'lorem',
skuname: 'skuname2',
token: 'dummy'
}
];
const getUserName = (username) => {
return new Promise(resolve => {
setTimeout(()=>resolve(username), 2000);
});
};
(async () => {
const resp = await Promise.all(input.map(({skuname}) => getUserName(skuname)));
console.log(resp);
})();
// Or
Promise.all(input.map(({skuname}) => getUserName(skuname)))
.then(resp => {
console.log(resp);
});
try
const productN = await this.getUsername(env,skuName,token);
console.log(productN);
Can you try doing this? Return your getDeviceName function in getUsername;
getUsername(env:string, skuName: string, token:string): Promise<any> {
return this.getDeviceName(env, skuName, token);
};
const productN = await this.getUsername(env, skuName, token);
console.log(productN);
I don't know why you use getUsername. since you can get the value in productN directly from getDeviceName.
like
const productN = await this.getDeviceName(env, skuName, token);
If you want to do any other things inside getUsername. you can make it return a promise.
getUsername(env:string, skuName: string, token:string): Promise<any> {
return New Promise(async (resolve,reject)=>{
try {
let value = await this.getDeviceName(env,skuName,token);
...
//all other things you want to do here
...
resolve(value);
} catch (error) {
reject(error)
}
}
};
const productN = await this.getUsername(env, skuName, token);
console.log(productN);
nb: I used try catch block for error handling, Ignore it if you don't want to.
I have this request handler on my node server. It has three MongoDB queries, and I want all the results to be returned, before the response is sent.
api.get('/getStats/:productID', (req,res)=>{
let data = {};
let dailySales = [];
let avgProduct = "";
let customers = [];
Sales.find({productID: productID}).then(
sales => {
dailySales = sales;
}
);
Products.find({}).then(
products => {
// Calculate Avg product here
avgProduct = result;
}
);
Customers.find({}).then(
customers => {
customers = customers;
}
);
data = {
dailySales,
avgProduct,
customers
};
res.json(data);
});
But running this returns
data: {
dailySales: [],
avgProduct: "",
customers: []
}
i.e. The Mongo response is returning before the data is run. Please how to I fix. Thank You
wait for all the promises to resolve before sending the actual response
const sales = Sales.find({productID: productID});
const allProducts = Products.find({});
const allCustomers = Customers.find({});
Promise.all([sales, allProducts, allCustomers])
.then(data => res.json(data));
you can try using the Promise.all where you can pass the MongoDB queries as parameter to it ,the promise will be resolved when all the queries return the result in the array
Try using the in-built util.promisify function along with
async-await to get data correctly!
const promisify = require('utils').promisify;
const salesFindOnePromise = promisify(Sales.find);
const productsFindAllPromise = promisify(Products.find);
const customersFindAllPromise = promisify(Customers.find);
findDailySalesByIdAsync = async (productID) => {
try {
return await salesFindOnePromise({ productID: productID });
} catch(err) {
throw new Error('Could not fetch the appropriate sales with productID');
}
}
findProductsAsync = async () => {
try {
return await productsFindAllPromise({});
} catch (err) {
throw new Error('Could not fetch sales!');
}
}
findCustomersAsync = async () => {
try {
return await customersFindAllPromise({});
} catch (err) {
throw new Error('Could not fetch customers!');
}
}
api.get('/getStats/:productID', async (req,res)=>{
try {
const dailySales = await findDailySalesByIdAsync(productID);
const avgProduct = await findProductsAsync();
const customers = await findCustomersAsync();
const data = {
dailySales,
avgProduct,
customers
};
return res.status(200).send(data);
} catch(err) {
console.err(`Failed because: {err}`);
throw new Error('Could not fetch data because of some error!');
}
});