I am new to node js. I learned am learning to execute MySQL queries using async/await instead of callback functionality.
I am able to get data on success but If any error occurs, I couldn't catch that error. Please suggest me how to achieve so.
My MySQL code to create a row in the education table
Education.create = async (newEducation) => {
try {
const res = await sql.query("INSERT INTO education SET ?", newEducation);
return await {id: res.insertId, ...newEducation};
}catch(err) {
// I couldn't catch DUPLICATE ENTRY ERROR or any other MYSQL generated error
console.log(": ---------------------------")
console.log("Education.create -> err", err)
console.log(": ---------------------------")
return err;
}
}
Related
I have a simple api to communicate with my mobile app and i have some updates to do.
I want to make 2 updates at the same function (or th same route) but i dont know if its possible.
Here is the dboperation part:
async function updateCusto() {
try {
let pool = await sql.connect(config);
let updateCusto = await pool.request()
.input('input_parameter1', sql.Int, CodOS)
.input('input_parameter2', sql.Int, CodProduto)
.query("update osproduto set custounit=produto.precocusto, valorunitario=produto.precosugerido from OSProduto INNER JOIN Produto ON OSProduto.CodProduto = Produto.Codigo where codproduto=#input_parameter2 and codos=#input_parameter1")
.query("Update OSProduto set sub=qtde*valorunitario where codos=#input_parameter1") //the second one, doenst work
return updateCusto.recordsets;
}
catch (error) {
console.log(error);
throw error;
}
}
and here is the route part:
router.route("/updateCusto").post((request, response) => {
CodOS = request.body.CodOs;
CodProduto = request.body.CodProduto;
dboperations.updateCusto(CodOS, CodProduto).then(result => {
console.log(result);
response.json("Update ok!");
})
.catch(error => response.json({ error }))
})
How can i do this? Is there a way to run the 2 updates on the same operation? Or do i need to create another operation to use on the same route, after the first update is made (and if so, how can i do that?).
It's definitely possible, in fact I would do it as a transaction, this way if one of the queries fails a rollback would be made in order to preserve the state of your database.
Here are my suggestions:
Read about database transactions
Replace pure SQL with an ORM such as Sequelize or KnexJS, it will help you to prevent errors by making queries calling methods such as await OsProduto.update({ where: { id: 0 }}, newData);
I have a SQLite database I am trying to add data to with the sqlite3 package. My query is as follows, and works in the SQLite command line.
'INSERT INTO `EVENTS`(`ID`,`EventName`,`EventSociety`,`BookerName`,`BookerEmail`,`BookerStudentID`,`BookerPhone`,`TimeStart`,`TimeEnd`,`EquipmentList`,`EventSearchYear`,`EventSearchMonth`,`EventSearchDay`) VALUES (NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);';
And I'm using this code to insert to the database in node.
db.run("begin transaction");
let sql = 'INSERT INTO `EVENTS`(`ID`,`EventName`,`EventSociety`,`BookerName`,`BookerEmail`,`BookerStudentID`,`BookerPhone`,`TimeStart`,`TimeEnd`,`EquipmentList`,`EventSearchYear`,`EventSearchMonth`,`EventSearchDay`) VALUES (NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);';
console.log(sql);
db.run(sql,(err) => {
res.send('ok');
});
db.run("commit");
Trying this in node hard crashes, with a Illegal instruction: 4. However, it is only happening on two tables, both with over 5 fields, in my database, and not any other smaller ones. Is there a character limit I'm unaware of?
To avoid crash, we need to handle error as below:
Example
The line db.run(sql, params, function (err) { in below example:
let sql = `INSERT INTO Users(id,firstName,lastName,email,password,permissionLevel) VALUES (?,?,?, ?,?,?)`;
let params = [uuid4(), "fn1", "ln1", "a#a2.com", "pwd1", 0];
db.run(sql, params, function (err) {
if (err) {
console.error("Error: Insert failed: ", err.message);
console.error("Error: Full error: ", err);
return;
}
console.log("insert success");
});
EDIT: I found out that "async" could be added to the function signature, and while the output does go in the proper order, I still get an error that I can't set headers after they are sent, even though I am not setting them anywhere else. I've modified the code to reflect this.
I'm having an issue with my Google Firestore api using ExpressJS. It seems that the result is sent before the Firestore query completes and I'm not sure why, as I'm not doing anything with res otherwise. It seems that Firestore queries are async but I don't know how to have my endpoint wait for the Firestore data before sending results. Here is my router code:
router.post('/some_endpoint/get_something', async function (req, res) {
console.log("Getting firestore data...")
let db_data = null;
let some_val = req.body.some_val;
let colRef = db.collection("some_collection");
await colRef.where("some_field", "==", some_val)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log("Still processing...")
db_data = doc.data()
})
res.json({ <---- This is where it breaks
status: 200,
data: db_data
})
})
.catch(function(error) {
console.log("Error getting doc: ", error);
})
console.log("We're done!")
});
This is the output order (EDIT with new output order):
Getting firestore data...
Still processing...
Error getting doc: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client...
We're done!
The error message is telling you that you're trying to send multiple responses, which is not valid. Here, your code is calling res.json() many times, once for each document in the query results:
querySnapshot.forEach(function(doc) {
console.log("Still processing...")
res.json({
status: 200,
data: doc.data()
})
})
You should only call res.json() once with the final result to send to the client, after you're done iterating the results.
I am developing a synchronizer between two databases (SQL Server and MySQL) with ElectronJS and Node.JS and everything is working fine, but I would like to execute the window.close() method to terminate the application when all tables are syncronized (which are done asynchronously within a for loop).
// I removed error and bank connection treatments because they are working
// Read json file that contains all tables and its columns (keys)
fs.readFile(ABSPATH + 'tables.json', 'utf8', async (err,json) => {
// Parse the content of the file into a JSON object
let vetor = JSON.parse(json)
// Foreach table
for (let i = 0; i < vetor.length; i++) {
// Read the table from SQL Server and save it falues into MySQL
await read(vetor[i].table,vetor[i].keys)
}
// Instead of closing, I'm just displaying this message on screen (for debugging)
document.body.innerHTML += "<h2>All data where inserted</h2>"
})
But as you can see, it is returning the final result before returning the functions, that is, they remain asynchronous:
Click here to see the image
I believe my error is at the time of saving the data in the following function because I tested it with console.log(), but I still can't make it synchronous:
con.connect(async err => {
// Begin MySQL Transaction
await con.beginTransaction(async err => {
// Clear the table
await con.query(`TRUNCATE TABLE ${table}`, err => {})
// Loop to insert all inputs into table
for (let i = 0; i < values.length; i++){
// Create and execute the query to input values into table
await con.query(createInsert(table,keys,values[0]), err => {})
}
// When all data are inputed, end Transaction
await con.commit(err => {
// Write in window that everything gonna allright
document.body.innerHTML += "<p>All data where successfully saved into " + table + ".</p>"
})
})
// End MySQL Transaction
})
Like georg had told me, the problem was that I was trying to await async functions, but the await only works with Promises.
I found the answer greetings to him and to this answer that I had received on StackOverflow in portuguese.
So, I just put my connection into a Promise, like this:
// Save datas into MySQL Database
function save(table, keys, values) {
return new Promise((res, rej) => {
// MSSQL returns a JSON object filled with informations that I don't want
// so I filter only what I want: the result of the query
values = values.recordset
// Start a new MySQL connection
let con = mysql.createConnection({
user: OUSER,
password: OPASS,
server: OHOST,
port: OPORT,
database: ODB
})
con.connect(err => {
if (err) {
alert(err)
window.close()
}
con.beginTransaction(err => {
// This function is just for DontRepeatYourself
rollBack(con, err, rej)
con.query(`TRUNCATE TABLE ${table}`, err => { rollBack(con, err, rej) })
con.query(createInsert(table,keys,values[0]), err => { rollBack(con, err, rej) })
con.commit(err => {
rollBack(con, err, rej)
document.body.innerHTML += `<p>All data where successfully registered into ${table}.</p>`
res()
})
})
})
})
}
I've searched on how to create a sqlite3 database with a callback in Node.js and have not been able to find any links. Can someone point me towards documentation or provide a 2-3 line code sample to achieve the following:
Create a sqlite3 database and catch an error if the creation fails for any reason.
Here is what I've tried:
let dbCreate = new sqlite3.Database("./user1.db", sqlite3.OPEN_CREATE, function(err){
if(!err){
logger.infoLog("Successfully created DB file: " + dbFileForUser + " for user: " + username );
} else {
logger.infoLog("Failed to create DB file: " + dbFileForUser + ". Error: " + err );
}
});
dbHandler[username] = dbCreate;
When I execute this, I get the following error:
"Failed to create DB file: ./database/user1.db. Error: Error: SQLITE_MISUSE: bad parameter or other API misuse"
This call without callback works just fine.
var customDB = new sqlite3.Database("./custom.db", sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE);
But in this, I will not know if I run into any errors while creating the Database.
Try this:
let userDB = new sqlite3.Database("./user1.db",
sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
(err) => {
// do your thing
});
Example.
#Irvin is correct, we can have a look at http://www.sqlitetutorial.net/sqlite-nodejs/connect/ and
check it says if you skip the 2nd parameter, it takes default value as sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE
and in this case if database does not exist new database will be created with connection.
sqlite3.OPEN_READWRITE: It is to open database connection and perform read and write operation.
sqlite3.OPEN_CREATE : It is to create database (if it does not exist) and open connection.
So here is the first way where you have to skip the 2nd parameter and close the problem without an extra effort.
const sqlite3 = require("sqlite3").verbose();
let db = new sqlite3.Database('./user1.db', (err) => {
if (err) {
console.error(err.message);
} else {
console.log('Connected to the chinook database.|');
}
});
db.close((err) => {
if (err) {
return console.error(err.message);
}
console.log('Close the database connection.');
});
And this is the 2nd way to connect with database (already answered by #Irvin).
const sqlite3 = require("sqlite3").verbose();
let db = new sqlite3.Database('./user1.db', sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE
, (err) => {
if (err) {
console.error(err.message);
} else {
console.log('Connected to the chinook database.');
}
});
db.close((err) => {
if (err) {
return console.error(err.message);
}
console.log('Close the database connection.');
});