Using a db query as a promise [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm trying to use sql queries as promises. I can't seem to get it to work:
query: (sql, args) => {
if (args) sql = mysql.format(sql, args);
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
console.log(err);
reject(Error(err.code));
}
connection.query(sql, (err, results) => {
connection.release(); // always put connection back in pool after last query
if (err) {
console.log(err);
resolve([]);
}
resolve(results);
});
});
});
},
And here is the query itself:
async function dbCall(sql, arg) {
let data = await db.query(sql, arg);
console.log(data);
data = data[0];
return data;
}
And here is the pool:
var pool = mysql.createPool({
host: 'localhost',
user: 'user',
password: 'pass',
database: 'db',
});
What I'm trying to do:
I'm trying to have it where it doesn't get hung up on async functions. I want it to return a value throughout a whole async function instead of inside of itself only.
Right now, it isn't working at all. However, when it is I would like row to be defined in my whole function instead of just inside the db.query.
I'm not sure if this makes sense, but if you need more clarification just ask anything.

Well if I understand your questions correctly you're misunderstanding how promises should be handled. Promises make use of a then() function to perform something only after the async request is finsihed.
It reads pretty well in plain English. Perform my async request THEN do something with the data.
Try this:
db.query(userSQL, username).then(res => console.log(res))
Additionally, you could use an async function. This allows use to handle async functions in a similar way to synchronous functions where your code will be executed sequentially without having to worry about chaining and nesting other code inside of then() functions
async function dbCall() {
let data = await db.query(userSQL, username);
console.log(data);
}
As a side note. This was super helpful to me when I was first getting into Promises.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Related

How to return the results of mySql query using express.js?

I am trying to get the results of my simple SELECT command to the index.js file, where I would like to have all records separated in a array. If I print the results in the database.js the JSON.parse just work fine. But if I want to return them and get them into the index.js where I need them, I always get undefined when I print it.
index.js CODE
const express = require('express');
const app = express();
const database = require('./database');
app.use(express.json());
app.use(express.urlencoded());
app.use(express.static('public'));
app.get('/form', (req,res) =>{
res.sendFile(__dirname + '/public/index.html' );
console.log(req.url);
console.log(req.path);
})
app.listen(4000, () =>{
console.log("Server listening on port 4000");
database.connection;
database.connected();
//console.log(database.select());
let results = [];
//results.push(database.select('username, password'));
let allPlayer = database.select('username');
console.log(allPlayer);
});
database.js CODE
let mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
database: 'minigames',
user: 'root',
password: 'root'
});
function connected(){
connection.connect((err) => {
if(err) throw err;
console.log("Connected...");
})
}
function select(attribute){
let allPlayer = [];
let sql = `SELECT ${attribute} FROM player`;
let query = connection.query(sql, (err, result, field) => {
if(err) throw err;
return Object.values(JSON.parse(JSON.stringify(result)));
})
}
module.exports = {connection, connected, select};
Understand that one of the main things that make JavaScript different from other languages is that it's asynchronous, in simple terms meaning code doesn't "wait" for the code before it to finish executing. Because of this, when you're trying to query a database, which takes some time, the code after it gets impatient and executes regardless of how to the query is doing. To solve this problem, the mysql package utilizes callbacks, which allows you to pass a function to it to execute once the query is finished with the queries result.
Because the library operates on callbacks, it doesn't return anything; that seems quite problematic for using it somewhere else, doesn't it?
To solve this problem, we can make our own callback. Or better yet, use the newer JavaScript feature called promises, where you can basically "return" anything from a function, even when you're in a callback.
Let's implement it with the query:
function select(attribute) {
return new Promise((resolve, reject) => {
let sql = `SELECT ${attribute} FROM player`;
let query = connection.query(sql, (err, result, field) => {
if(err) return reject(err);
resolve(Object.values(JSON.parse(JSON.stringify(result))));
});
});
}
To "return" from a promise, we pass a value to the resolve function. To throw an error, we call the reject function with the error as the argument.
Our new function is rather easy to use.
select("abcd").then(result => {
console.log("Result received:", result);
}).catch(err => {
console.error("Oops...", err);
});
You might look at this code and go, "Wait a minute, we're still using callbacks. This doesn't solve my problem!"
Introducing async/await, a feature to let you work just with that. We can call the function instead like this:
// all 'await's must be wrapped in an 'async' function
async function query() {
const result = await select("abcd"); // woah, this new await keyword makes life so much easier!
console.log("Result received:", result);
}
query(); // yay!!
To implement error catching, you can wrap you stuff inside a try {...} catch {...} block.

Undefined variable async JavaScript

I just started out learning Node.js / Express and I still have difficulties with the Asynch functions. I made some functions to interact with a postgresql database (with some tutorials), and selecting rows from data is going fine but for some reason something is going from with deleting the rows. Here is an example of a function that is going well:
const getPlayers = () => {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM Players ORDER BY p_id ASC', (error, results) => {
if (error) {
reject(error)
}
resolve(results.rows);
})
})
}
Now the following function is not going well. Console.log(id) gives the right number, but it seems that id is undefined when executing the query and I suspect that it has to do with Asynch/synch. Now Asynch is new for me, so I am also not an expert on what is going wrong.
Here is the function that is nog going good:
const deletePlayer = (id) => {
return new Promise(function(resolve, reject) {
pool.query('DELETE FROM Players WHERE player_id = ?' , [id], (error,results) => {
if (error) {
reject(error)
}
resolve(`Player deleted with ID: ${id}`)
})
})
}
The function call:
app.delete('/laProjects/:id', (req, res) => {
players_model.deletePlayers(req.params.id)
.then(response => {
res.status(200).send(response);
})
.catch(error => {
res.status(500).send(error);
})
})
How to debug this situation
Don't automatically assume it is an async issue. First try some simple console.log steps:
const deletePlayer = (id) => {
console.log("Started deletePlayer with id: ",id) ///////////
return new Promise(function(resolve, reject) {
console.log("Inside the promise, id is the same, namely: ",id) ///////////
pool.query('DELETE FROM Players WHERE player_id = ?' , [id], (error,results) => {
if (error) {
reject(error)
}
resolve(`Player deleted with ID: ${id}`)
})
})
}
See if 'id' is what you expect it to be
If you don't see any console.log messages printed, maybe, as #steve16351 suggests, you are editing deletePlayer but actually calling another functiondeletePlayers?
In general, avoid using the word "async" for promises used without the "async" keyword
When Promises first arrived in Javascript, they were the practical tool for asynchronous programming, so people sometimes used the term "async" for them in speech.
However since the async keyword arrived, it is better not to use the word "async" for things that are not that keyword.
Simple glossary
Blocking code: a program that simply waits (preventing any other code running) while some external process happens.
Callbacks: the oldest form of asynchronous programming in JS. You tell JS to run a certain function only after some external event has happened.
Promises: a more convenient and readable way to achieve the same effect as callbacks. You can imagine the process to be constructed out of hidden callbacks.
async keyword: an even more convenient and readable way to achieve the same effects as callbacks and promises. It is implicitly made out of promises, although it protects you from having to think about how to construct a new promise.
In response to you reporting that id is 5 inside the promise
This tells us that your original assumption, that the error is due to a variable being undefined, is incorrect. id has the expected value.
Therefore the error is that the API is giving an error in response to this call:
pool.query(
'DELETE FROM Players WHERE player_id = ?' ,
[5],
(error,results) => {
if (error) {
reject(error)
} else {
resolve(`Player deleted with ID: ${id}`);
}
}
)
So why don't you run exactly that, in simplified form like this:
pool.query(
'DELETE FROM Players WHERE player_id = ?' ,
[5],
(error,results) => {
console.log("Error:",JSON.stringify(error,null,2),"Results:",JSON.stringify(error,null,2))
}
)
This sends an explicit request to pool.query, and explicitly reveals the output. I don't know the format the pool.query API is expecting: perhaps it is not quite right?

How does AWS.DynamoDB.DocumentClient.put() and promise() work in Lambda?(Javascript)

I'm very new to javascript in general and I'm doing a school project that builds a simple lambda function to save some data to DynamoDB from an HTTP request.
First, I had this version:
exports.handler = async (event) => {
var params = {
TableName: 'graph',
ReturnConsumedCapacity: "TOTAL",
Item: null
};
for (let input of event.inputs) {
params.Item = {
'key' : input.key,
'value' : input.value
};
await DynamoDB.DocumentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
});
}
};
To my shallow understanding, an async function like the handler should wait for any await statement to finish executing, but I got nothing in the database. But even for some reasons if the lambda function execution didn't wait for DynamoDB.DocumentClient.put() to finish, wouldn't the DynamoDB.DocumentClient.put() finish on its own after the lambda has returned?
Then I followed some other people's examples and added promise() to the end:
exports.handler = async (event) => {
var params = {
TableName: 'graph',
ReturnConsumedCapacity: "TOTAL",
Item: null
};
for (let input of event.inputs) {
params.Item = {
'key' : input.key,
'value' : input.value
};
await DynamoDB.DocumentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
}).promise();
}
};
Now even though it successfully put data into the database, the log shows 6 'Success' messages where I only put 3 pairs of key-value pairs. After some playing around, I realize the 'Success' messages appear once in the first callback, twice in the second, and three times in the third. I have no clues when it behaves like this at all. Can someone shed some light on this, please? Thank you
You're mixing callbacks and promises. Callbacks were the preferred way to deal with async code (and still is preferred by some i guess), until promises were introduced.
It's not recommended to mix these two for the same purpose.
This would be more correct as you're using the built-in 'then' method of the Promise class:
await DynamoDB.DocumentClient.put(params)
.promise()
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
It doesn't break anything using the callback as well though. Here is a really good answer that explains promises:
Aren't promises just callbacks?
When it comes to it logging 6 times, that doesn't make any sense if the array passed to the loop only has 3 items. If you could provide the output in your original post, I'll see if i can make sense of it and give you an updated answer.

Using async/await with callback functions

I'm trying to build a service layer on top of mongo. I have a User object which has an array of referenced Achievements.
After I've authenticated the user by JWT or some other means, I enter the service layer and query the relationship as follows.
findForUser(userId: string | Types.ObjectId): Promise<Achievement[]> {
return new Promise((resolve) => {
UserSchema.findOne({ _id: userId },
async (err: any, user: User) => {
const AchievementMap: Achievement[] = [];
if (err) throw new Error(err);
user.achievements?.forEach((a) => {
// #ts-ignore
AchievementMap.push(a);
});
resolve(AchievementMap);
});
});
}
What is the async/await approach to returning the result of the callback method passed into UserSchema.findOne?
findOne returns an awaitable object - so you don't need to pass a callback to it. Don't try mixing callbacks with async/await. The only way to return the value from the callback, as a result of the constructed promise is by using resolve (only available in the promise executor).
Instead, make it all async - functionally similar but far cleaner.
async findForUser(userId: string | Types.ObjectId): Promise<Achievement[]> {
const user = await UserSchema.findOne({ _id: userId });
const AchievementMap: Achievement[] = [];
user.achievements?.forEach(a => {
AchievementMap.push(a);
});
return AchievementMap;
}
What is the async/await approach to returning the result of the callback
The async and await keywords are tools to manage promises. They aren't tools to manage callbacks.
The entire point of the code you have in the question is to wrap a promise based API around a function that deals in callbacks.
Now you have a promise you can await the return value of findForUser.
You can't use async and await instead of creating a promise.

Can't use a variable from an await mongodb query

I'm having a problem using the mongodb query result on another query.
I hope this code explains it (it's written inside an async function) - Please notice that i'm using created_comment._id in the second query:
let created_comment = await Comment.create(new_comment, (err, newReturnedComment)=>{
if(err){
console.log(err);
}
});
await User.findOneAndUpdate({_id: req.user._id},{ $addToSet: {commentsIds: created_comment._id} },
function(err, updated_user) {
if (err) {
console.log(err);
}
});
so even though i'm using await in the first query, when i try to access the created_comment variable i'm not getting anything. is it because create and findOneAndUpdate are not promises? Can you please refer me to a guide that explains whats the best way to make such queries on a nodejs backend?
Thank you.
Do not pass a callback to mongodb functions if you want to use async/await and expect the calls to return promises. Just write
try {
const created_comment = await Comment.create(new_comment);
const updated_user = await User.findOneAndUpdate({_id: req.user._id}, {$addToSet: {commentsIds: created_comment._id}});
} catch(err) {
console.log(err);
}

Categories

Resources