JavaScript async await doesn't work inside forEach loop - javascript

I have few queries to a database which I want to gather into a transaction.
let t = await db.sequelize.transaction()
try {
let adr = await addressRepo.add(address, t)
let user = await userRepo.add(email, password, name, surname, phone, NIP, REGON, id_number, adr.id, t)
await userRoleRepo.add(user.id, user_role, t)
if (languages != null) {
languages.forEach(async function (language) {
await userLanguageRepo.add(user.id, language.id, language.main, t)
})
}
await t.commit()
res.status(201).json(user)
} catch (error) {
await t.rollback()
}
According to above code, the transaction is created and all queries are included except of those in forEach loop. As a result I get:
Executing (fb270893-9146-43b7-a35e-8960ea386513): START TRANSACTION;
Executing (fb270893-9146-43b7-a35e-8960ea386513): INSERT INTO `address` (`id`,`country`) VALUES (DEFAULT,'country');
Executing (fb270893-9146-43b7-a35e-8960ea386513): INSERT INTO `user` (`id`,`email`,`password`,`name`,`surname`,`active`,`address_id`,`created_at`,`updated_at`) VALUES (DEFAULT,'a15','$2a$10$7uImQNl0T12CZLUB0Asxwu8yCGUa/eZnbr8TATX8V/tnnO8erdYzy','John','Dee','0',15,'2017-08-28 07:44:03','2017-08-28 07:44:03');
Executing (fb270893-9146-43b7-a35e-8960ea386513): INSERT INTO `user_role` (`user_id`,`role_id`) VALUES (7,1);
Executing (fb270893-9146-43b7-a35e-8960ea386513): COMMIT;
(node:5873) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: commit has been called on this transaction(fb270893-9146-43b7-a35e-8960ea386513), you can no longer use it. (The rejected query is attached as the 'sql' property of this error)
(node:5873) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:5873) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: commit has been called on this transaction(fb270893-9146-43b7-a35e-8960ea386513), you can no longer use it. (The rejected query is attached as the 'sql' property of this error)
I looked at async commit is execute before forEach loop. How can I execute forEach loop before commit?

Instead of forEach one should use for of loop.
I found the answer at this post.

Related

node-postgres throwing connection error when chaining 2 queries together via promises and then trying to end the connection

I'm getting strange behaviour in node-postgres when inserting data into tables. When running this block of code, it works perfectly:
client
.query(
format(
"INSERT INTO precipitation(xref, yref, calendarmonth, val) VALUES %L",
dataToWrite
)
)
.then(() => {
client.end();
})
.catch((err) => {
console.log(err);
client.end();
});
Note that I'm using pg-format to format an array of arrays (dataToWrite) in order to insert each array as a row into the table with a single statement. There's about 60,000 rows of data being created.
I want to chain another query before this, to insert data to another table on the same db. However, this code throws an error:
client
.query(
"INSERT INTO meta_data(header, units, vers, coords, refs) VALUES ($1, $2, $3, $4, $5)",
metaRows
)
.then(() => {
client.query(
format(
"INSERT INTO precipitation(xref, yref, calendarmonth, val) VALUES %L",
dataToWrite
)
);
})
.then(() => {
console.log("test")
client.end();
})
.catch((err) => {
console.log(err);
client.end();
});
The first statement executes correctly, and metaRows is inserted into meta_data without issue. But now the statement that was working in the first code block above is throwing an error and the dataToWrite variable's arrays aren't being inserted into the table. This is the error in the terminal:
(node:20116) UnhandledPromiseRejectionWarning: Error: Connection terminated
at Connection.<anonymous> (/home/george/NorthCoders/Job_Applications/jba-data-challenge/node_modules/pg/lib/client.js:132:36)
at Object.onceWrapper (events.js:420:28)
at Connection.emit (events.js:326:22)
at Socket.<anonymous> (/home/george/NorthCoders/Job_Applications/jba-data-challenge/node_modules/pg/lib/connection.js:58:12)
at Socket.emit (events.js:314:20)
at TCP.<anonymous> (net.js:673:12)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:20116) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:20116) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
The error hints that closing the connection via client.end() is causing the issue - I have tried removing this and the data does seem to be inserted when running the code again, although I have to manually close the connection in the terminal or open a new shell to check this. But I am confused as to why the client.end() would be an issue, as it isn't when executing the query in the first code block, and as far as I know using promises should wait for the statement to complete before running the next then() block. However, it looks like the then() block closing the connection runs before the statement has finished executing, as the "test" console log in the second code block is being logged before the error is thrown.
I also do have a catch() block to handle errors in the promise chain, so I'm not sure what the error is referring to there.
Any advice on what's happening and how to get around this would be appreciated. I'd like to keep using promises if possible. I can attach the SQL code if helpful, but there's not much to see and I don't think it's the cause of the issue.

How can I get a Minecraft player's UUID from their username in NodeJS?

I know there are lots of other posts asking this same questions, but none of the others had the solution to my problem. I am using NodeJS and DiscordJS to create a discord bot, and I need to get the UUID of a Minecraft player from just their username, which will be provided as an argument in the command.
This is the function I have created to do this, however it doesn't seem to be working.
function getId(playername) {
const { data } = fetch(`https://api.mojang.com/users/profiles/minecraft/${args[2]}`)
.then(data => data.json())
.then(({ player }) => {
return player.id;
});
}
args[2] is the third argument of the command, which is formatted like this: <prefix> id <playername>. fetch is part of the 'node-fetch' npm module, which I have installed. I call the function when the command is sent, and it fetches the data from Mojang's API, but it can't get the UUID. This is the error:
(node:39416) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'id' of undefined
at C:\Users\archi\OneDrive\Documents\Programming\Discord Bots\Hypixel Discord Bot\index.js:161:21
at processTicksAndRejections (internal/process/task_queues.js:94:5)
(node:39416) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:39416) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
It is saying it cannot read the property of 'id', which if you use the Mojang API, is the key for the UUID of a player. Any ideas?
Try using the playername instead of args[2] in the request URL, and making it return a promise. There's also no need to use { player }, as the object the API returns doesn't have a player propriety. Just use player as the argument for the arrow function.
function getId(playername) {
return fetch(`https://api.mojang.com/users/profiles/minecraft/${playername}`)
.then(data => data.json())
.then(player => player.id);
}
Then call it like so in your code:
// Using .then (anywhere)
getId(args[2]).then(id => {
console.log(`ID is ${id}`)
})
// Using await (inside of an async function)
const id = await getId(args[2])
console.log(`ID is ${id}`)

Using loop with async/await inside loop + nodejs

Hello in my nodejs api i need fetch data inside the loop and then again need to do a loop and save a data in another table how should i achive that?
Here is some snippet that i have tried but not succeeded for the same
async myAPIname(){
let _this = this;
try {
const bets = await Bet.find({gameId:ObjectId(request.matchId)}).lean()
bets.map(async (bet) => {
let Users = await Users.findOne({_id:ObjectId(element.userId)}).lean();
Users.parentTree.map(async (user) => {
console.log(user);
// also over here based on the some calculation need to save the data in another table
})
})
} catch (error) {
_this.res.send({ status: 0, message: error });
}
}
Also in above snipped tried with foreach loop as well but not succeeded
and error from above spinet like this:
(node:30886) UnhandledPromiseRejectionWarning: ReferenceError: Cannot access 'Users' before initialization
at /var/www/html/api/app/controllers/SomeController.js:228:30
at Array.map (<anonymous>)
at SomeController.myAPIname (/var/www/html/api/app/controllers/SomeController.js:227:18)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:30886) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:30886) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:30886) UnhandledPromiseRejectionWarning: TypeError: Assignment to constant variable.
at /var/www/html/api/app/controllers/SomeController.js:220:27
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:30886) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
Any Help will really appreciated
I can see two problems:
firstly the await inside a map call doesn't work like you think. It will work fine in a for-of loop but not in a map, foreach etc.
https://zellwk.com/blog/async-await-in-loops/ has a good an explanation as anywhere.
Secondly where you are calling let Users = Users.findOne, the compiler thinks that Users on the left hand side of the assignment is the same as the Users on the right hand side so it complains that when its calling Users.findOne, Users isn't initialised.
to use asynchronous handling with Array.prototype.map() you have to wrap it with Promise.all() and wait for it to fulfill.
!! however notice that iterations are executed in asynchronous way, not waiting for previous iteration to settle.
const sleep = async (time = 3000) => new Promise(resolve => setTimeout(resolve, time));
(async () => {
const array = [1,3,4,2];
console.log('start', array);
const mapped =await Promise.all(array.map(async e => {
await sleep(e * 1000);
console.log(e);
return `done for ${e}`;
}));
console.log('end', mapped);
})();

How I can create a file using multiple .chunk files?

I have more .chunk files which I fetch using node-fetch and using these files I want to create another file by "gathering them together" somehow.
I tried with this:
var fileStream = await fs.createWriteStream(`./paks/${file.Filename.slice(26)}`)
//below code is in a loop, above isn't in a loop
await fetch(chunkURL)
.then(async res => {
if(chunks.indexOf(chunk) == chunks.length - 1) await res.body.pipe(fileStream, { end: true })
else await res.body.pipe(fileStream, { end: false })
})
but the file is corrupted after it finishes, I also tried with flieStream.write(res.body, { end: true }) instead of res.body.pipe(fileStream, { end: true }) but I get the following error:
(node:12110) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be one of type string or Buffer. Received type object
at validChunk (_stream_writable.js:265:10)
at WriteStream.Writable.write (_stream_writable.js:300:21)
at /root/api/getUpdate.js:97:87
at processTicksAndRejections (internal/process/task_queues.js:85:5)
at async /root/api/getUpdate.js:94:57
(node:12110) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:12110) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

client.channels.get(id).send() not working

So a discord bot I'm creating has a twitch notifications, and it uses snekfetch to create a looping request function. On the return of the function I have client.channels.get(id).send(embed) however it doesn't message the channel id which I've given it.
const api = `https://api.twitch.tv/helix/streams?user_login=${streamer}`;
snekfetch.get(api).set('Client-ID', "XXXXXXXXXXXXXX").then(r => {
if (r.body.stream === null) {
setInterval(() => {
snekfetch.get(api).then(console.log(r.body))
}, 30000);
} else {
const embed = new discord.RichEmbed()
.setAuthor(
`${r.body.data.user_name} is live on Twitch`,
)
.setThumbnail(`http://static-cdn.jtvnw.net/ttv-boxart/live_user_${streamer}-500x500.jpg`)
.addField('Views', `${r.body.data.viewer_count}`, true)
return bot.channels.get(XXXXXXXXXXXX).send("TEST");
}
});
I have named my client bot so instead of client.channels it's bot.channels
It should in theory send the TEST message to whatever channel id I give it, however instead I get an error.
(node:62565) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'send' of undefined
at /Users/XXXXXXX/Desktop/HelperBot/main.js:61:50
at processTicksAndRejections (internal/process/task_queues.js:89:5)
(node:62565) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:62565) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
your error has to do with that not all channels are text channels. Before you can send a message it has to be sure it can. so you could check if that's the case with the function .isText() when you have checked that it is the type should change to text channels which are dm text and news at this moment. those have the .send function
The error said it can't find the .send("Test") function of something that is not defined.
So the error come from bot.channels.get(XXXX)
bot.channels return a collection. If you search a specific item of this collection. You need to use .find and not .get
More info about .find here : https://discord.js.org/#/docs/main/stable/class/Collection?scrollTo=find

Categories

Resources