I'm performing mysql query using nodejs/mysql.
After the first result set, I will loop through the results set and query a second table.
1) Why 'for' works and 'foreach' doesn't? What's the proper looping way to achieve what I need?
2) item = { ...item, images: rows } in the getImage function also doesn't work, why?
3) How to let the console.log show the modified results? If I use 'await', the console.log(rows) should show the modified results right?
const getImages = async (item, key) => {
let sql = await connection.format('SELECT * from `images` WHERE id = ?', [item.id]);
const [ rows , fields ] = await connection.execute(sql);
item['images'] = rows
item = { ...item, images: rows } //'<-- this method doesn't work.
return item
}
let sql = await connection.format(`SELECT * from table ORDER BY a.listing_id LIMIT ?,?`, [0,10])
var [rows, fields] = await connection.execute(sql);
// rows.forEach(getImages) //'<-- this does not work when uncommented
// rows = rows.forEach(getImages) //'<-- this also does not work when uncommented.
for (let i = 0; i < rows.length; i++) { //'<-- but this works
rows[i] = await getImages(rows[i], i);
}
console.log(rows) //<----- this doesn't show modified results on terminal console
res.json(rows) //<----- browser can see the modified results on browser console
You have to pass to the foreach method the proper handler on each item:
let new_rows = Array()
rows.forEach(row => {
new_rows.push(await getImages(row, i))
});
Plus, if you want to get the images on another array you should use map, its cleaner:
let new_rows = rows.map(row => {
return await getImages(row, i)
});
Because forEach not returning anything .So better use Array#map
rows = rows.map(getImages)
Related
Hi this is my function i am calling this from my controller like this:
var getLastPoll = await socketModel. getPollOptionsByPollId(data.poll_id);
but i am getting empty array as result in controller but when i logged result in my model it is returning the data of array containing two objects ? where i am doing mistake can someone help?
const getPollOptionsByPollId = async (poll_id) =>
{
var querySql1 = "SELECT * FROM public.group_poll_options
WHERE option_poll_id= $1 AND
option_status = $2 ORDER BY option_id";
var queryParams1 = [poll_id, "active"];
var pollOptions = await db.query(querySql1, queryParams1);
var result = [];
if (pollOptions.rowCount != 0) {
pollOptions.rows.map(async value => {
var voteCount = await totalvotesbypolloption(poll_id, value.option_id);
console.log("voteCount",voteCount);
var data = {
option_id: value.option_id,
option_poll_id: value.option_poll_id,
option_value: value.option_value,
option_status: value.option_status,
option_created_at: value.option_created_at,
option_votes: voteCount
}
result.push(data);
});
}
return result;
}```
Using async/await when iterating over arrays with map, forEach, etc, doesn't do what you expect it to do. All iterations will finish before totalvotesbypolloption is called even once.
Replace map with with for...of:
for (const value of pollOptions.rows) {
var voteCount = await totalvotesbypolloption(poll_id, value.option_id);
console.log("voteCount",voteCount);
var data = {
option_id: value.option_id,
option_poll_id: value.option_poll_id,
option_value: value.option_value,
option_status: value.option_status,
option_created_at: value.option_created_at,
option_votes: voteCount
}
result.push(data);
}
var listUsers= [];
for(let item of list){
var profile = await getOne(item.updatedBy);
var gettedUsers = await User.find(queryData).populate({path: "profiles"});
var users = gettedUsers.filter(user => user._id !== profile._id);
if(users) {
for(let gettedUser of users) {
if(!listUsers.includes(gettedUser.profile._id)){
listUsers.push(gettedUser.profile._id);
// do some stuff for the getted user
}
}
}
}
console.log(listUsers); // i get duplicated users
I had added this array list 'listUsers' to filter users and then for each one of them i can do some stuff, but the problem is that i get duplicated users.
Someone could help me ?
The solution is that I changed :
listUsers.includes(gettedUser.profile._id)
to :
var contains = (list, element) => list.some(elem =>{
return JSON.stringify(element) === JSON.stringify(elem);
});
I really don't know waht's the problem but i think I was comparing objects instead of strings. Anyway this solved it ;)
I have different document id for every loop and when I query inside the forEach loop query is working but not pushing the obj into the array
function getAllDonations() {
donations = [];
const user_session_data = sessionStorage.getItem('LoginInfo');
const parse_user_login_data = JSON.parse(user_session_data);
let TABLE_NAME = "donation_favourites";
let get_requests_qry = App.db.collection(TABLE_NAME);
get_requests_qry.where('user_id', '==', parse_user_login_data.user_id).get().then(snapshot => {
let changes = snapshot.docChanges();
changes.forEach(change => {
var one_item = change.doc.data();
let TABLE_NAME1 = "donation_requests";
let get_requests_qry1 = App.db.collection(TABLE_NAME1);
get_requests_qry1.doc(one_item.donationId).get().then(snapshot => {
donations.push(snapshot.data())
});
});
console.log("checking the data",donations.length) //this length is not coming
});
}
If you want to read the files in use forloop but it is not recommended for large loop for small loop it is ok
if you want to read files parallel use forEach
You can also do it with async and await instead forLoop
await Promise.all(changes.map(async (change) => {
var one_item = change.doc.data()
let TABLE_NAME1 = "donation_requests";
let get_requests_qry1 = App.db.collection(TABLE_NAME1);
var snapshot1 = await get_requests_qry1.doc(one_item.donationId).get()
donations.push(snapshot1.data())
}));
I have a react app that pulls data from firebase. It adds data to the array fine. But cannot be accessed. calling the index returns undefined and length of array is 0. but when you print the array the console shows there is an element inside. Whats going on?
componentWillMount() {
itemsRef.on('value', (snapshot) => {
let items = snapshot.val();
let keys = Object.keys(items);
for(var i = 0; i < keys.length; i += 1) {
let k = keys[i];
let name = items[k].name;
let start = items[k].start;
this.state.timers.push( {
name: name,
start: start
} );
}
});
console.log(this.state.timers); // shows an array with stuff in it
this.setState({timers: this.state.timers}); // timers dont get added
// you cant even access elements in the array.
// ex: this.state.timers[0] returns undefined, but the console shows that it exists when the whole array is printed.
}
You shouldn't mutate directly your state like you do in the `this.state.timers.push({})``
You should do something like that:
itemsRef.on('value', (snapshot) => {
const items = snapshot.val();
this.setState({
timers: [
...this.state.timers,
...Object
.keys(items)
.map(key => {
const { name, start } = items[key];
return { name, start };
}),
],
});
});
You shouldn't push directly to the state. Instead you should to something like this:
ES6 variant
const timers = [...this.state.timers];
timers.push({ name, start });
this.setState({ timers })
async traverse(url) {
const ts = new TournamentScraper()
const ms = new MatchScraper()
const results = []
const tournaments = await ts.run(url)
for(let href of tournaments.map(t => t.href)){
let matches = await ms.run(href)
let pages = ms.getPages()
let seasons = ms.getSeasons()
//console.log(pages)
//console.log(seasons)
results.push(matches)
for(let href of pages) {
//console.log(href)
matches = await ms.run(href)
//console.log(matches)
results.push(matches)
}
}
return results
}
TournamentScraper returns an array of objects, which typically looks like this:
{name: 'Foo', href: 'www.example.org/tournaments/foo/'}
The link points to the tournament's last season's first page. This page contains the links to the other seasons and a paginator (if any).
MatchScraper's run returns some data, and sets the instance's dom property. getPages() and getSeasons() consumes this property and each returns an array of links.
The problem that results contains only the first batch of matches. I can see the 2nd page's matches in the console log, but they are not in the results array when traverse returns.
I found this rule which is against await in for loop. The problem, that I have to wait for ms.run(href), because it sets dom, and getPages() and getSeasons() needs it to be set, to extract the needed links.
I think this should work. It utilizes Promise all rather than for loops
const run = href => ms.run(href);
async function getMatches(href) {
const out = [];
const matches = await run(href);
const pages = ms.getPages();
out.push(matches);
if(pages.length) {
const pageResults = await Promise.all(pages.map(href => run(href)));
out.push(...pageResults);
}
return out;
}
async function traverse(url) {
const ts = new TournamentScraper();
const ms = new MatchScraper();
const tournaments = await ts.run(url)
const matches = await Promise.all(tournaments.map(t => getMatches(t.href)));
return matches.reduce((a, b) => {
a.push(...b);
return a;
}, []);
}