Looping vue object in express/sql - mysql

I have a form that adds a project with x number of persons.
I'm using Nuxt with express and MySQL database.
I have a route method like this that inserts a project to my database:
app.post('/addNewProject', function (req, res) {
var sql = "INSERT INTO project (name, startDate, endDate) VALUES ('"+req.body.projectName+"', '"+req.body.projectStart+"', '"+req.body.projectEnd+"'); INSERT INTO persons (projectID, name, workHours) VALUES (LAST_INSERT_ID(), '"+req.body.persons[0].personName+"', '"+req.body.persons[0].personHours+"')";
connection.query(sql, function (err, rows) {
if (err) throw err
res.send(rows)
})
})
The persons is a vue object persons: [{ personName: '', personHours: '' }], that can be filled in the form.
So since its persons[0] now, it only adds the first item to the database.
Im wondering if there is a way to loop the object inside this sql variable.
And I think I have to loop it here since I need the LAST_INSERT_ID() because I need to get the projectID that is a AUTO_INCREMENT primary key in the project table.
I have tried to use sql wihle loop but it doesn't seem to work here.

Related

How to send multiple requests with Axios?

I'm working on a react registration form which contain some fields (idStudent(primary key & auto increment), first name, last name, ....., faculty, prerequisites), I'm using Formik & yup for validation.
Later on, I have to link my app with a recommendation system (recommend a final year project to students) based on prerequisites and the obtained grades in some subjects.
At first, I used just one table to store the data coming from the form in frontend,
student(firstname, lastname, ... ,prerequisites)
A student can select prerequisites from a react select that contain prerequisites according to the faculty (example : if a student study computer science, the react select will show only computer science prerequisites like react, angular, machine-learning ....).
Taking into consideration a student can have multiple prerequisites, so the prerequisites column in students table will contain multiple id's of the selected prerequisites,
The prerequisites are stored in an other table in my database ( prerequisites(idFaculty, idPrerequisites, prerequisite) )
I know that I can store multiple id's in one column using a JSON file but after some researches here on Stackoverflow in some previous posts, I found that it's difficult to deal with JSON especially if I want to update a column.
So I created another table to store the selected prerequisites by a student when registering
(studentPrerequisites(idStd (foreign key reference to idStudent from students table), idPrerequisite(foreign key reference to idPrerequisites from Prerequisites table))
The problem I'm facing is how to send two post's requests via axios, taking into
consideration that maybe I should use a loop to store multiple rows in case a student select multiple Prerequisites.
This is what I did :
My backend file
app.post("/registerStudent", (req, res) => {
const faculty = req.body.faculty;
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const phone = req.body.phone;
const email = req.body.email;
const password = req.body.password;
db.query(
"INSERT INTO students (email, password, firstName, lastName, faculty, phone) VALUES (?,?,?,?,?,?)",
[email, password, firstName, lastName, filiere, phone],
(err, result) => {
if (err) {
console.log(err);
} else {
// store chosen prerequisites
//result.insertId is the current idStudent of the student who registering
const idStd = result.insertId;
const idPrerequisite = req.body.idprerequis;
db.query(
"INSERT INTO studentPrerequisites (idStd, idPrerequisite) VALUES (?,?)",
[idFiliere, idPrerequisite],
(err, result) => {
if (err) {
console.log(err);
} else {
res.send("Values Inserted");
}
}
);
}
}
);
});
My frontend code
const onSubmit = (values, actions) => {
Axios.post("http://localhost:3001/registerStudent", {
faculty: values.faculty,
firstName: values.firstName,
lastName: values.lastName,
phone: values.phone,
email: values.email,
password: values.password,
})
.then(() => {
//preId is an array that contains the selected prerequisites(id's) from react select
//I try to use a for loop to store multiple of prerequisites dynamically in case a
//student select multiple prerequisites
for (let i = 0; i < preId.length; i++) {
idPrerequisites: preId[i],
}
})
.then(() => {
console.log("success!");
});
actions.resetForm();
};
It might be best to let the backend handle multiple prereqs by passing in an array of prereqs to your request. I'd also use Knex and async/await to avoid a lot of .then chaining and to make use of transactions. Transactions will revert all queries if any errors occur within the transaction. Knex also makes querying databases super easy with built-in methods instead of writing raw SQL. You should also be using object destructuring instead of doing firstName = req.body.firstName, lastName = req.body.lastName, etc. You can learn more about knex and getting your db connected to it here: https://knexjs.org/guide/#node-js
Also, WHY ARE YOU NOT HASHING YOUR PASSWORDS? That is the most basic security you should be doing at a minimum!

Nodejs passport setup confusion

I have been trying to setup my Nodejs MySQL database configuration. I found this passport.js config for MySQL on Github. The config works properly but there is a part that I do not understand.
var insertQuery = "INSERT INTO users ( email, password ) values ('" + email +"','"+ password +"')";
console.log(insertQuery);
connection.query(insertQuery,function(err,rows){
newUserMysql.id = rows.insertId;
return done(null, newUserMysql);
});
I am confused about the insertID field. The table I am using does not have a field called insertID. It does however have a field named ID. I tried changing that line to
newUserMysql.id = rows.Id;
bu doing so gives me:
Error: Failed to serialize user into session
Leaving it as it is gives me no error
Looks like insertID has nothing to do with the ID field of my table but I do not understand what it means
That probably represents LAST_INSERT_ID() which is the ID of the last row inserted.
The response of an INSERT is not "rows" but a result object, so maybe better named it'd be:
connection.query("...", function(err, result) {
newUserMysql.id = result.insertId;
return done(null, newUserMysql);
});
It's important to note that using Promises dramatically simplifies your code, and async/await can take that even further. This could be as simple as:
let result = await connection.query("...");
newUserMysql.id = result.insertId;
return newUserMysql;
Where that's inside an async function with a Promise-driven database library like Sequelize. You're not handling the potential errors in your first case. In the second you'll get exceptions which will wake you up when there's problems.

Error from ending connection from 'query inside query'

I am using mysql node module and having an error of Error: Cannot enqueue Query after invoking quit. from my source code which has a block that does 'update if exists, otherwise insert' (similar logic as in another question I asked).
The reason I include it in node is that the definition of 'duplicates' is customized.
I have tested my source code and it was able to successfully perform 'update if exists, otherwise insert' to my table, but I am not able to close my connection, as for my insert/update query reside in the search query.
const insertQueue = (results) => {
_.forEach(results, (values, key) => {
_.map(values, (value) => {
let query = 'SELECT index FROM table WHERE (document=? AND ((document NOT like \'PERSONAL:%\' AND username=?) OR (document like \'PERSONAL:%\' AND serial=?)))';
connection.query(query, [value.document, key, value.serial], function(error, rows){
if (error) {
console.log(error);
}
else {
//Ideally there should be only one entry, but still return an array to make the function error-safe
let indices = _.map(rows,'index');
if (_.isEmpty(indices)) {
//sqlInsert and sqlUpdate are defined elsewhere and has sql query defined with 'connection.query(..)' similar to this
sqlInsert(key, value.serial, value.document, value.lastRun);
}
else {
_.each(indices, (index) => {
sqlUpdate(index,value.lastRun);
});
}
}
});
});
});
connection.end();
}
sqlInsert and sqlUpdate are defined elsewhere and has sql query defined with connection.query(..) similar to the function above.
I understand that connection.query(..) is asynchronous, and I put my connection.end() in the very end of the function. But I don't understand why I am still getting the error of Cannot enqueue Query after invoking quit every time I call my insertQueue.
Also if I replace my sqlInsert(...); and sqlUpdate(...) with some testing command (with no db sql query execution), the error will be gone.
Is there any reasons for this?
first thing you should not call async function inside loop (map, forEach, for, while or anyone).
second it's worst idea to fire query in loop.
mysql.js provide method for bulk insert
from official doc https://github.com/mysqljs/mysql
Nested arrays are turned into grouped lists (for bulk inserts), e.g.
[['a', 'b'], ['c', 'd']] turns into ('a', 'b'), ('c', 'd')
take an example
connection.query('INSERT INTO posts SET ?', [['a', 'b'], ['c', 'd']], function (error, results, fields) {
if (error) throw error;
// ...
});
third i think lastRun is datetime. you can choose mysql type current timestamp and now no need to worry this in query,

Node.js, After inserting not shown in list query

After adding a product to the mysql database, I want to dump all the products with the latest product. This product is being added with an algorithm to the database and I want to list all the products immediately afterwards. Already tried "async", "promise" etc.
--When the table is empty--
connection.query("INSERT INTO `products` (id, name, price)", function (error, results, fields) {}); //inserted one row
connection.query("SELECT * FROM `products`", function (error, results, fields) {}); // show only []
after second insertion list query show only first row but not second. The main problem is this and table has two rows.
Thank you.
Query data when insert is done:
connection.query("INSERT INTO `products` (id, name, price)",
function (error, results, fields) {
connection.query("SELECT * FROM `products`", function (error2, results2, fields2){});
});
connection.query("INSERT INTO products(id, name, price)",
function (error, results, fields) {
if(error) return ....
else{
connection.query("SELECT * FROM products", function
(error,results,fields2){
var returned_data = results;
console.log(results);
//res.send(results);
})
}});
Would be the way to go, but check whether you're inserting the data the right way at all, since you haven't provided the way you do it, I doubt that any async method would fail you itself.
EDIT on request: You can pass the results to a variable, but you can only use it inside that function if you don't (because of its scope) , ie res.send or res.end it (if you're using this inside a request, which I'm guessing you are), or console.log it or just write it to a file.

store mysql query results in redis

I am trying to use redis to store a list of users and weather or not they are online or offline and displaying that information to other users.
I am fairly new to node and I believe that I need to use either a list or sorted sets.
when it gets to the console.log(reply); line it only shows "Object"
I think I need to loop through the results of the query to build the list but I am not really sure 1) how to loop through the results directly in the server application and 2) how to build the list or sorted set based on that query.
Any advice or suggestions would be greatly appreciated.
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'password',
database : 'users'
});
var redis = require('redis')
, client = redis.createClient();
connection.connect();
connection.query('SELECT * FROM user_profile', function(err, rows, fields)
{
if (err) throw err;
client.set('string key', rows[0], redis.print);
client.get("string key", function (err, reply) {
console.log(reply);
});
});
connection.end();
1) I assume rows contains an array of objects, each object representing a user data record.
client.set('string key', rows[0], redis.print);
is storing the whole first object of rows array, you can use a foreach statement to loop over all values returned.
You are saving the whole object in redis, but you only need the online/offline state 1 or 0. Besides, you can store only strings in redis keys (see Redis Keys Docs and Redis Set Docs)
2) You don't need a list or sorted sets only for online/offline state of a user, unless you need some sorting operations later.
You can use simple keys, I suggest using a pattern like this for key name: "user:".
// assuming that user_name property exists, holds username data "david" and it's unique
client.set("user:"+row[0].user_name, 0, redis.print); // stores key "user:david" = "0";`
Then to retrieve it use:
client.get("user:"+row[0].user_name);
So, your sql query callback function could look like this:
function(err, rows, fields) {
if (err) throw err;
rows.forEach(function(element, index, array){
client.set('user:'+element.user_name, 0, redis.print);
client.get("user:"+element.user_name, function (err, reply) {
console.log(reply);
});
});
}
Please note that the user name must be unique. You can use user ID's if not