I had a MongoDB and I want to change a value of a bunch of templates.
I guess I get the variable and replace the old value.
findTemplates.forEach(async templateName => {
const template = await getTemplate( templateName )
const templateBody = await replaceBody( template.body )
templateBody.replace('string', 'another-string');
})
async function getTemplate (siteName) {
const id = await emailTemplate.model.findOne({
'name.de': siteName,
language: 'en',
businessUnit: '24ede462ad78fd0d4fd39dfa',
}).distinct('_id')
const body = await emailTemplate.model.findOne({
'_id': id,
}).distinct('body')
return {
id: id,
body: body
}
}
function replaceBody( body ) {
return body.replace('one', 'two')
}
unfortunately, I get the following error:
UnhandledPromiseRejectionWarning: TypeError: body.replace is not a functiontemplateBodyHow can I use the replace function in my forEach async function?
I rewrote your sample, so I can simulate it, this sample works as you expected, but no exception was thrown. So, the only mistake I have detected was in this line:
// You must not put await here because replace body does not return a Promise.
const templateBody = replaceBody( template.body )
const allTemplates = []
for (let i = 0; i <= 10; i++) {
allTemplates.push({
_id: faker.random.uuid(),
'name.de': faker.internet.domainName(),
language: faker.random.locale(),
businessUnit: faker.random.uuid(),
body: faker.lorem.paragraph()
})
}
const findTemplates = allTemplates.map(item => item['name.de'])
const emailTemplate = {
model: {
findOne: params => {
const found = allTemplates.find(item => params._id ? item._id === params._id : item['name.de'] === params['name.de'])
const result = Object.assign({}, found, params)
result.distinct = function (key) {
return Promise.resolve(this[key])
}
return result
}
}
}
async function getTemplate (siteName) {
const id = await emailTemplate.model.findOne({
'name.de': siteName,
language: 'en',
businessUnit: '24ede462ad78fd0d4fd39dfa',
}).distinct('_id')
const body = await emailTemplate.model.findOne({
'_id': id,
}).distinct('body')
return {
id: id,
body: body
}
}
function replaceBody( body ) {
return body.replace('one', 'two')
}
findTemplates.forEach(async templateName => {
try {
const template = await getTemplate( templateName )
// You must not put await here because replace body does not return a Promise.
const templateBody = replaceBody( template.body )
console.log(templateBody.replace('string', 'another-string'))
} catch (err) {
console.err(`Error procesing template: ${templateName}: ${err}`)
}
})
/**
* Alternatively you can do:
Promise.all(findTemplates.map(async templateName => {
const template = await getTemplate( templateName )
// You must not put await here because replace body does not return a Promise.
const templateBody = replaceBody( template.body )
console.log(templateBody.replace('string', 'another-string'))
}).catch(err => console.err)
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.min.js"></script>
So respect to your question: How can I use the replace function in my forEach async function? The answer is you can use replace as you do (but fix the line, and check what #t-j-crowder commented).
If the body is not string, then you should inspect what kind of object it is, and if it has a replace function (or not), and if this replace function returns (or not) a Promise.
Related
I have a function that returns the guilds prefix in Discord.JS:
getprefix.js:
const GuildSchema = require("../Database/Models/GuildConfigs");
const { DEFAULT } = require("./config");
const getprefix = async (id) => {
const guildConfigs = await GuildSchema.findOne({
GuildID: id,
});
let PREFIX = DEFAULT;
if (guildConfigs && guildConfigs?.Prefix) {
PREFIX = guildConfigs?.Prefix;
}
};
module.exports = { getprefix };
I call the function in another file using this:
let prefix = getprefix(message.guild.id);
prefix.then(() => {
console.log(prefix);
});
The problem is it returns this in the console:
Promise { '!' }
Is it possible to just return the actual prefix that is inside the quotes with out the Promise?
Yes, but you must return the value from the async function.
getprefix.js:
const GuildSchema = require("../Database/Models/GuildConfigs");
const { DEFAULT } = require("./config");
const getprefix = async (id) => {
const guildConfigs = await GuildSchema.findOne({
GuildID: id,
});
let PREFIX = DEFAULT;
if (guildConfigs && guildConfigs?.Prefix) {
PREFIX = guildConfigs?.Prefix;
}
return PREFIX;
};
module.exports = { getprefix };
and change the call:
let prefix = getprefix(message.guild.id);
prefix.then((value) => {
console.log(value);
});
First you must return a value from your async function called getprefix. Secondly you must console.log the result of the promise returned by getprefix function instead of the promise itself :
const getprefix = async (id) => {
const guildConfigs = await GuildSchema.findOne({GuildID: id});
if (!guildConfigs || !guildConfigs.Prefix) {
return DEFAULT;
}
return guildConfigs.Prefix;
};
getprefix(message.guild.id).then(prefix => console.log(prefix));
There is a code like this:
const axios = require('axios');
const cheerio = require('cheerio');
let data = null;
const parseNewCorporations = async (iter) => {
let link2 = 'https://www.finanzen.net/aktien/' + iter.finanzen_net + '-aktie';
try{
await axios.get(link2)
.then(res => res.data)
.then(res => {
let html = res;
$ = cheerio.load( html, { decodeEntities: false } );
let bigData = iter;
let price = $('div.snapshot-headline div.col-sm-7 div.row.quotebox:first-child div.col-xs-5.col-sm-4.text-sm-right.text-nowrap').text();
let currency = $('div.snapshot-headline div.col-sm-7 div.row.quotebox:first-child div.col-xs-5.col-sm-4.text-sm-right.text-nowrap span').text();
price = price.replace(currency, '').replace(',', '.');
})
}
catch(e){
console.log(e.message, ', id =', iter.id, ", finanzen_net = "+iter.finanzen_net);
await getAdditionPriceBilanzGuv(iter);
}
};
const getAdditionPriceBilanzGuv = async (iter) => {
//console.log('111', iter); // **here the code works correctly**
let link = 'https://www.finanzen.net/bilanz_guv/'+ iter.finanzen_net;
try{
await axios.get(link)
.then(res => res.data)
.then(res => {
console.log('getAdditionPriceBilanzGuv', iter);
// **here the code works NOT correctly**
})
}
catch(e){
if(e.message == 'Request path contains unescaped characters'){
console.log('Request path contains unescaped characters');
console.log({paramSubLink: iter.finanzen_net, corporations_id: iter.id});
}
else{
console.log('paramCorporationsId: ', iter.id);
//console.log('err- ', e);
}
}
};
function getApiData(){
// get request
return axios.get("https://seo-gmbh.eu/invest/daily.php" , {
})
.then(response => {
return response.data;
})
.catch(function (error) {
console.log(error);
});
}
async function new_corporations() {
data = await getApiData();
let ii = 1;
for (let iter of data.new_corporations) {
//await parseNewCorporations(iter);
ii++;
await setTimeout(function(){
parseNewCorporations(iter);
}, ii*3000);
}
//console.log(arrayCurrency);
}
new_corporations();
After calling the parseNewCorporations () function, the catch () exception is triggered as a result of which
the corresponding messages can be seen in the console.
The problem is that when this error appears, you need to run the following function getAdditionPriceBilanzGuv () with the iter parameter, and inside the body oftry {}you need to get this parameter, which cannot be done.
At the very beginning (outside the body of try {}) of this function (where it is indicated by a comment that the code works), it is possible to get this parameter.
Question:
What am I missing and how can I get this parameter in a newly called function inside the body of try {}?
If it is impossible to do this, what alternative implementations can be for solving this problem?
P.S. In this case, a parsing library is used cheerio
If you use async / await, you don't want thens
let res = await axios.get(link2)
let $ = cheerio.load(res.data)
I need to get datas with nested foreach, but I can't fill my array.
At the end of this code I would like to have an array (segId) with my datas but it is empty (because of aynschronous).
I read that I had to use Promise.all but I can't beacause my promise are nested
I'm beginner so my code is far from perfect
How can I do that ?
async function getActivities(strava, accessToken)
{
const payload = await strava.athlete.listActivities({'access_token':accessToken, 'after':'1595281514', 'per_page':'10'})
return payload;
}
async function getActivity(strava, accessToken, id)
{
const payload = await strava.activities.get({'access_token':accessToken, 'id':id, 'include_all_efforts':'true'})
return payload;
}
async function getSegment(strava, accessToken, id)
{
const payload = await strava.segments.get({'access_token':accessToken,'id':id})
return payload
}
var tableau = []
var segId = []
const activities = getActivities(strava, accessToken)
activities.then(value => {
value.forEach((element, index) => {
const activity = getActivity(strava, accessToken, element['id'])
activity.then(value => {
value['segment_efforts'].forEach((element, index) => {
const segment = getSegment(strava, accessToken, element['segment']['id'])
segment.then(value => {
segId.push(value['id'])
})
//console.log(segId)
});
});
})
}) console.log(segId)
Regards
PS : Sorry for my english ...
Something like this should work. You need to always return the inner promises to include them in your promise chain. Consider splitting the code into functions to make it more readable.
getActivities(strava, accessToken).then(activities => {
return Promise.all(activities.map(elem => {
return getActivity(strava, accessToken, elem['id']).then(activity => {
return Promise.all(activity['segment_efforts'].map(elem => {
return getSegment(strava, accessToken, elem['segment']['id']).then(segment => {
segId.push(segment['id']);
});
}));
})
}));
})
.then(_ => {
console.log(segId);
});
I have a file with some functions:
const API = {
async getComments() {
var data = [];
var url = 'http://url.com/wp-json/wp/v2/comments';
const serviceResponse = await fetch(
url,
)
.then((serviceResponse) => {
return serviceResponse.json();
} )
.catch((error) => console.warn("fetch error:", error))
.then((serviceResponse) => {
for (i in serviceResponse) {
data.push({
"key": serviceResponse[i]['id'].toString(),
"name": serviceResponse[i]['author_name'],
"content": serviceResponse[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": serviceResponse[i]['author_avatar_urls']['96'],
"date": serviceResponse[i]['date'].replace('T', ' ')
});
}
global.comments = data;
return data;
});
}
}
export { API as default }
In another file I include the file, and make the call:
var comments = await API.getComments(key);
console.log (comments);
But I receive undefined, I tried to create a function with bind:
this.newGetComments = API.getComments.bind(this); with the same result. I used a global variable, but I want to remove the globals vars.
/* Few suggestions;
1. you are not returning anything from the getComments method. Please return fetch(url) response.
2. you should return something from the catch block to handle the error.
*/
const API = {
async getComments() {
var url = 'http://url.com/wp-json/wp/v2/comments';
var response = await fetch(url)
.then(serviceResponse => {
return serviceResponse.json();
})
.then(serviceResponse => {
let data = [];
// rest of your code.
return { success: true, data };
})
.catch(error => {
console.warn('fetch error:', error);
return { success: false, error };
});
return response
},
};
var comments = await API.getComments(key);
if (comments.success) {
// handle the success case comments.data
} else {
// handle the Error case comments.error
}
console.log(comments);
An async function always returns a promise as you aren't returning anything from the getComments methods, the function automatically resolves and returns undefined(Promise.resolve(undefined)). You need to return serviceResponse from the getComments method to get the fetch api's response.
You can try something like below:
async componentDidMount() {
let data = [];
const result = await this.getComments();
const jsonData = await result.json();
console.log('Result ==> ', jsonData.serviceResponse);
jsonData.serviceResponse.map(data =>
data.push({
"key": data['id'].toString(),
"name": data[i]['author_name'],
"content": data[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": data[i]['author_avatar_urls']['96'],
"date": data[i]['date'].replace('T', ' ')
})
);
console.log('Data ==> ', data);
}
async getComments() {
const result = await fetch('http://url.com/wp-json/wp/v2/comments', {method: 'GET'});
return result;
}
After calling fetchNotes from the addNote function it shows me undefined as push method is not defined in the addNote function
const fs = require('fs');
const fetchNotes = ()=>{
fs.readFile('data.json',(err,notes)=>{
if(err){
// return empty array if data.json not found
return [];
}else{
// return Object from data found data.json file
return JSON.parse(notes)
}
});
}
const saveNotes = (notes) =>{
fs.writeFile('data.json',JSON.stringify(notes),()=>{
console.log('Notes is successfully saved');
});
}
const addNote = (title, body)=>{
const note = {
title,
body
}
const notes = fetchNotes();
//Push method not defined
notes.push(note);
saveNotes(notes);
return note;
}
module.exports.addNote = addNote;
It returns undefined because when you are returning in the callback you are not exactly returning from the fetchNotes function itself.
Maybe you can use the readFileSync and don't use callback or maybe you can make it a promise and use async/await
const fetchNotes = () => {
return new Promise((res, rej) => {
fs.readFile('data.json', (err, notes) => {
if (err) {
// return empty array if data.json not found
res([]);
} else {
// return Object from data found data.json file
res(JSON.parse(notes));
}
});
});
}
const addNote = async (title, body) => {
const note = {
title,
body
}
const notes = await fetchNotes();
//Push method not defined
notes.push(note);
saveNotes(notes);
return note;
}
Alternatively, you can use utils.promisify
return JSON.parse(notes) does not store this value inside fetchNotes because it is asynchronous, so you get the content of the file later in time.
To do it asynchronously, you can use async/await :
const fetchNotes = () => {
return new Promise((resolve, reject) => {
fs.readFile('data.json', (err,notes) => resolve(JSON.parse(notes)));
})
}
const addNote = async (title, body) => {
// ...
const notes = await fetchNotes();
notes.push(note);
saveNotes(notes);
return note;
}
You can also do it synchronously :
const fetchNotes = () => JSON.parse( fs.readFileSync('data.json') );
const notes = fetchNotes();