How to use Promise with nested foreach - javascript

I am finding all users wallets in nested foreach loop but i am unable to figure out where to use resolve() for return callback,
function genwallets() {
return new Promise((resolve, reject) => {
var i = 0;
try {
db.users.findAll({}).then((users)=>{
db.supportedTokens.findAll({}).then((tokens)=>{
users.forEach(function(user) {
tokens.forEach(function(token) {
db.wallets.findOne({where:{userId: user['id'], supportedTokenId: token['id']}}).then((wallet)=>{
console.log(JSON.stringify(wallet));
})
});
});
})
});
} catch (err) {
console.log(err);
}
});
}

forEach doesn't work with promises. either use for...of or Promise.all something like this
function genwallets() {
return new Promise((resolve, reject) => {
var i = 0;
try {
db.users.findAll({}).then(users => {
db.supportedTokens.findAll({}).then(tokens => {
for(const user of users) {
for(const token of tokens) {
db.wallets
.findOne({
where: { userId: user["id"], supportedTokenId: token["id"] }
})
.then(wallet => {
console.log(JSON.stringify(wallet));
});
}
}
});
});
} catch (err) {
console.log(err);
}
});
}
by the way you dont need to wrap it in promise.
You could simplify this using async/await
async function genwallets() {
const users = await db.users.findAll({});
const tokens = await db.supportedTokens.findAll({});
for(const user of users) {
for(const token of tokens) {
const wallet = await db.wallets
.findOne({
where: { userId: user["id"], supportedTokenId: token["id"] }
});
}
}
}

Related

I'm getting an error when I search the database and I don't know how to solve it

I'm making a request to my database, I set the functions as asynchronous and to wait, but it still returns me undefined or Promise { pending }
how do I just return it when I have the result?
export const getGerente = async (req, res) => {
var query = "SELECT * FROM inventory;"
const r = await select(query)
console.log(r)
return res.json({message:"teste"})
}
export async function select(query) {
var teste = await client.connect(() =>{
client
.query(query)
.then((resultado) => {
console.log('sucess!!');
return resultado.rows
/*
const rows=resultado.rows
rows.map(x =>{
console.log(x.name)
})*/
})
.catch((erro) => {
console.log("erro: " + erro.message);
})
.then((teste) => {
console.log('Finished execution, exiting now');
process.exit();
});
})
}
result: Promise { pending }
I'm calling her for a request
Your select function is not awaiting the client.connect properly.
Try this for select function -
export async function select(query) {
const promisifiedRows = new Promise((resolve, reject) => {
client.connect((err) => {
if (err) {
reject(err); // err in connecting
} else {
console.log('Connected!');
client.query(query, (err, rows) => {
if (err) {
reject(err); // err while exceuting the query
} else {
resolve(rows);
}
});
}
});
});
const rows = await promisifiedRows();
return rows;
}

How to retrieve values from node-oracledb toQueryStream() as a Promise

While trying to get the rows from resultSet using toQueryStream() I can only find the rows in console. But not able to return value using promises as toQueryStream() function uses eventListener to resolve rows. My code is given below please suggest to get the row values.
function getPosCounter() {
return oracledb.getConnection(kcdConnStr)
.then(function (conn) {
return conn.execute(`BEGIN GETPOSCOUNTER(:CV_1); END;`, { // EXECUTE ORACLE PROCEDURE
CV_1: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR } //CURSOR DEFINED FOR OUT PARAM
})
.then((result) => {
var resRows = new Array();
var resultSet = result.outBinds.CV_1; //RESULT SET FOR OUTPUT
var queryStream = resultSet.toQueryStream(); //QUERYSTREAM INITIALIZED FOR CURSOR VALUES
var consumeStream = new Promise((resolve, reject) => {
queryStream.on('data', function (row) {
console.log(row);
});
queryStream.on('error', reject);
queryStream.on('close', resolve);
})
.then(rows => {
console.dir(rows); //RETURN ROW VALUES
});
})
.catch((err) => {
conn.close();
console.error(err);
return 'failure';
})
});
}
Before this issue I faced, I was not aware about the nodeJs-Stream feature which is quiet difficult to understand for me. So I found a documentation on Oracle Community about getting the rows from result set. Make it possible in the below way.
function getPosCounter() {
return oracledb.getConnection(kcdConnStr)
.then(function (conn) {
return conn.execute(`BEGIN USP_POSCOUNTER(:CV_1); END;`, { // EXECUTE ORACLE PROCEDURE
CV_1: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR } //CURSOR DEFINED FOR OUT PARAM
})
.then((result) => {
var resRows = [];
var resultSet = result.outBinds.CV_1; //RESULT SET FOR OUTPUT
var queryStream = resultSet.toQueryStream(); //QUERYSTREAM INITIALIZED FOR CURSOR VALUES
return consumeStream = new Promise((resolve, reject) => {
queryStream.on('data', (row) => {
resRows.push(row); //STORE ROWS IN TO BLANK ARRAY
});
queryStream.on('error', reject);
queryStream.on('close', () => {
resolve(resRows); //RETURN ON RESOLVING ALL THE ROWS
conn.close();
});
});
})
.catch((err) => {
conn.close();
//console.error(err);
return 'failure';
})
});
}
Instead of fiddling with promises and streams, you could code like this:
const oracledb = require('oracledb');
const dbConfig = require('./dbconfig.js');
if (process.platform === 'darwin') {
oracledb.initOracleClient({libDir: process.env.HOME + '/Downloads/instantclient_19_8'});
}
async function run() {
let connection;
try {
connection = await oracledb.getConnection(dbConfig);
await connection.execute(
`create or replace procedure usp_poscounter(p out sys_refcursor) as
begin
open p for select postal_code from locations order by location_id;
end;`);
const r = await getPosCounter();
console.dir(r, { depth: null });
} catch (err) {
console.error(err);
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
}
async function getPosCounter() {
let conn;
try {
conn = await oracledb.getConnection(dbConfig); // should really use a pool instead
const result = await conn.execute(
`BEGIN USP_POSCOUNTER(:CV_1); END;`,
{ CV_1: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR } }
);
let row, outRows = [];
while ((row = await result.outBinds.CV_1.getRow())) {
outRows.push(row);
}
// With node-oracledb 5.2 you will be able to simplify this loop to be the
// following one line. Note with any node-oracledb version, if the number
// of rows is large, then you will want your architecture to deal with
// batches of rows insteading of returning one big array.
//
// const outRows = await result.outBinds.CV_1.getRows(); // empty arg gets all rows
return (outRows);
} catch (err) {
console.error(err);
} finally {
if (conn) {
try {
await conn.close();
} catch (err) {
console.error(err);
}
}
}
}
run();

AWS GameLift ThrottlingException: Rate exceeded when attempting to retrieve multiple PlayerSessions via JS SDK

I'm trying to retrieve ALL the data on all the Fleets in our GameLift, to be displayed on a React-powered CMS site.
Currently our page retrieves the Fleets (via listFleets), the Fleet Attributes (via describeFleetAttributes), and Game Sessions (via describeGameSessions).
Here's the code for all of that:
requestGameLiftData = async () => {
const gamelift = new AWS.GameLift();
try {
const { FleetIds } = await new Promise((resolve, reject) => { // Get Fleet IDs
gamelift.listFleets({}, function(err, data) {
if (err) { reject("Fleet id error"); }
else { resolve(data); }
});
});
const { FleetAttributes } = await new Promise((resolve, reject) => { // Get Fleet Attributes by IDs
gamelift.describeFleetAttributes(
{ FleetIds: FleetIds },
function(err, data) {
if (err) { reject("Fleet attributes error"); }
else { resolve(data); }
}
);
});
await new Promise((resolve, reject) => { // Save Fleet Attributes to state
this.setState(
{ fleetList: [...FleetAttributes] },
() => { resolve(); }
);
});
const instancePromiseArr = [];
const gameSessionPromiseArr = [];
const playerSessionPromiseArr = [];
const { fleetList } = this.state;
for (let fleet of fleetList) {
instancePromiseArr.push(this.getFleetInstances(fleet, gamelift));
gameSessionPromiseArr.push(this.getFleetGameSessions(fleet, gamelift));
}
let instanceData; // Get all Instances of every Fleet
try { instanceData = await Promise.all(instancePromiseArr); }
catch (err) { throw new Error("Fleet instances error"); }
let gameSessionData; // Get all Game Sessions of every Fleet
try { gameSessionData = await Promise.all(gameSessionPromiseArr); }
catch (err) { throw new Error("Fleet game session error"); }
fleetList.forEach((fleet, index) => { // Nesting game sessions and instances inside their respective fleets
fleet["Instances"] = instanceData[index].Instances;
fleet["GameSessions"] = gameSessionData[index].GameSessions;
});
await new Promise((resolve, reject) => {
this.setState(
{ fleetList: [...fleetList] },
() => { resolve(); }
);
});
this.setState({isFetched: true});
} catch (error) { this.setState({isFetched: true}); }
};
getFleetInstances = (fleet, gamelift) => {
return new Promise((resolve, reject) => {
gamelift.describeInstances(
{ FleetId: fleet.FleetId },
function(err, data) {
if (err) { reject("Fleet instances error"); }
else { resolve(data); }
}
);
});
};
getFleetGameSessions = (fleet, gamelift) => {
return new Promise((resolve, reject) => {
gamelift.describeGameSessions(
{ FleetId: fleet.FleetId },
function(err, data) {
if (err) { reject("Fleet game sessions error"); }
else { resolve(data); }
}
);
});
};
Now I have to get the Player Sessions. To that end, I added the following:
let playerSessionData; // Before the "Nesting"
try { playerSessionData = await Promise.all(playerSessionPromiseArr); }
catch (err) { throw new Error("Player session error"); }
getPlayersInSession = (gameSession, gamelift) => {
return new Promise((resolve, reject) => { // Function to get Player sessions, outside of requestGameLiftData
gamelift.describePlayerSessions(
{ GameSessionId: gameSession.GameSessionId },
function(err, data) {
if (err) { reject("Fleet player sessions error"); }
else { resolve(data); }
}
);
});
};
And then modified the Get all Game Sessions portion to the following:
try {
gameSessionData = await Promise.all(gameSessionPromiseArr);
for (const gameSessionItem of gameSessionData) {
for (const data of gameSessionItem.GameSessions) {
playerSessionPromiseArr.push(this.getPlayersInSession(data, gamelift, delay));
}
}
} catch (err) { throw new Error("Fleet game session error"); }
And nested it in:
fleetList.forEach((fleet, index) => { // Nesting game sessions and instances inside their respective fleets
fleet["Instances"] = instanceData[index].Instances;
for (const gameSession of gameSessionData[index].GameSessions) {
gameSession['PlayerSessions'] = [];
for (const playerSessions of playerSessionData) {
if (playerSessions.PlayerSessions.length > 0) {
for (const playerSessionItem of playerSessions.PlayerSessions) {
if (playerSessionItem.GameSessionId === gameSession.GameSessionId) {
gameSession['PlayerSessions'].push(playerSessionItem);
}
}
}
}
}
fleet["GameSessions"] = gameSessionData[index].GameSessions;
});
This works... sometimes. Most of the times, I get a ThrottlingException: Rate exceeded and 400 Bad Request. This doesn't happen in other regions with significantly less fleets, so I thought it was related to the sheer number of requests made at once (as of this writing, 8 for the fleets, 8 for GameSessions, and no less than 28 for the PlayerSessions). So I tried adding a delay:
for (const gameSessionItem of gameSessionData) {
let delay = 0;
for (const data of gameSessionItem.GameSessions) {
delay += 50;
playerSessionPromiseArr.push(this.getPlayersInSession(data, gamelift, delay));
}
}
getPlayersInSession = (gameSession, gamelift, delay) => {
return new Promise(resolve => setTimeout(resolve, delay)).then(() => {
return new Promise((resolve, reject) => {
gamelift.describePlayerSessions(
{ GameSessionId: gameSession.GameSessionId},
function(err, data) {
if (err) { reject("Fleet player sessions error"); }
else { resolve(data); }
}
);
});
});
};
Which didn't work, of course. Is there anything I'm missing? Or is there another approach to this, to get all the data in one sitting without making too many requests?

Iterating through list and make sequential network calls

How do i iterate through a list and make sequential network calls using a sdk?
I am trying to use Coinbase's Node sdk and get the first 10 transactions for all accounts.
I have a list of accounts, and i iterating through them and calling client.account, client.transactions, and client.transactions(pagination). And im adding the results to an array of transactions and returning that array.
I couldn't get this to work with async/await or request-promises.
Any ideas?
https://developers.coinbase.com/api/v2#transactions
var rp = require('request-promise');
var coinbase = require('coinbase');
var client = new coinbase.Client({ 'apiKey': 'keyStuff', 'apiSecret': 'secretStuff' });
var accountList = ['acct1','acct2','acct3',];
var transactionList = [];
try {
let ps = [];
accountList.forEach(acctId => {
var account = client.getAccount(accountId, null);
ps.push(rp(account));
});
Promise.all(ps)
.then(responses => {
for (var i = 0; i < responses.length; i++) {
var result = responses[i];
rp(result.account.getTransactions(null))
.then(res => {
res.pagination = 10;
return rp(result.account.getTransactions(null, res.pagination));
}).catch(err => console.log(err))
.then(txns => {
try {
if (txns.length > 0) {
txns.forEach(function(txn) {
var transaction = {
"trade_type": "",
"price": ""
};
transaction.trade_type = txn.type;
transaction.price = txn.native_amount.amount;
transactionList.push(transaction);
});
}
}
catch (err) {
console.log(err);
}
});
}
}).catch(err => console.log(err));
return transactionList;
//-------------------------------------------------------------------
// if (accountList.length > 0) {
// for (let acctId of accountList) {
// console.log("account id: " + acctId);
// await delayTransactions(acctId);
// }
// console.log("got here last");
// return transactionList;
// }
}
catch (error) {
console.log(error);
}
The commented-out delay method has nested async calls like this:
await client.getAccount(accountId, async function(err, account) {
if (err) {
console.log(err);
}
else {
await account.getTransactions(null, async function(err, txns, pagination) {
.
.
.
Solved it by using async/await and promises. awaiting the coinbase methods wouldn't work because they aren't async functions (surprise!).
function delayedMethod() {
new Promise(resolve => {
client.getAccount(accountId, async function(err, account) {
if (err) {
console.log(err);
}
else {
account.getTransactions(null, async function(err, txns, pagination) {
.
.
.
resolve();
});
}

Promise.all inside another Promise.all seems to be exiting before its done and shows warning of not returning from a promise

I am using this function to be called in another Promise.all. But I always get this warning: Warning: a promise was created in a handler but was not returned from it.
Also the function deleteFutureAppointments() seems to exit from the original promise.all and starts doing other works in that promise.all chain.
function deleteFutureAppointments() {
Appointment.findAll(
{ where:
{
pro_id, client_id, from_datetime_utc: {
$gt: new Date()
}
}
})
.then((appointments) => {
if (!appointments) {
return new Promise((resolve) => resolve());
}
const promises = appointments.map((id) => {
const appointmentQuery = { where: { client_id } };
const appointmentSMIQuery = { where: { appointment_id: id.get("appointment_id") } };
return AppointmentMedia.destroy(appointmentSMIQuery)
.then((result) => {
if (result) {
removeAppointmentMedia.push(id.get("appointment_id"));
}
AppointmentService.destroy(appointmentSMIQuery);
})
.then(() => IndexAppointmentCalendar.destroy(appointmentSMIQuery))
.then(() => Appointment.destroy(appointmentQuery));
});
return Promise.all(promises);
})
.catch((err) => {
next(err);
});
}
Looks like you aren't returning the Promise from AppointmentService.destroy - might be your issue. I'd restructure as:
function deleteFutureAppointments() {
Appointment.findAll({ where: {
pro_id, client_id,
from_datetime_utc: { $gt: new Date() }
} }).then(appointments => {
return Promise.all(appointments.map(appointment => {
var id = appointment.get("appointment_id");
const appointmentSMIQuery = { where: {
appointment_id: id
} };
return AppointmentMedia.destroy(appointmentSMIQuery).then(result => {
if (result)
removeAppointmentMedia.push(id);
return AppointmentService.destroy(appointmentSMIQuery);
})
.then(() => IndexAppointmentCalendar.destroy(appointmentSMIQuery))
.then(() => Appointment.destroy({ where: { client_id } }));
}));
})
.catch((err) => {
next(err);
});
}

Categories

Resources