use mysql to update specific field(s) using expressjs - mysql

I am developing a middleware using express.js with mysql(new to mysql) and in my situation I have built this patch method to update the table. but the issue is I dont want to pass the entire field set to update specific fields out of many. so whats the preferred way to do this so that whatever fields I will send in request body those fields should be updated only.
const updateCompany = (req, res, next) => {
const cid = req.params.cid;
const {
company_id,
company_name,
company_address_line1,
company_address_line2,
company_email,
company_phone,
longitude,
latitude
} = req.body;
var myquery = `UPDATE Company_Master SET company_name="${company_name}",company_address_line1="${company_address_line1}",company_address_line2="${company_address_line2}",company_email="${company_email}",company_phone="${company_phone}",longitude=${longitude},latitude=${latitude} WHERE company_id = "${cid}"`
conn.query(myquery, (err, result) => {
if (err) {
console.log("err" + err);
} else {
res.status(201).json(req.body);
}
})
}

You can do as follows
const updateCompany = (req, res, next) => {
const cid = req.params.cid;
let
allowedcolumns = ["company_name", "company_address_line1", ... ], //all columns that can be updated
stmts = [],
values = [];
for (let c of allowedcolumns) {
if (c in req.body) { //check if there is a value for that column in the request body
stmts.push(`${c} = ?`),
values.push(req.body[c]);
}
}
if (stmts.length == 0) {
return res.sendStatus(204); //nothing to do
}
values.push(cid);
conn.query(`UPDATE Company_Master SET ${stmts.join(", ")} WHERE company_id = ?`, values, (err, result) => {
if (err) {
console.log("err" + err);
res.sendStatus(400);
} else {
res.status(200).json(req.body);
}
})
}
allowedcolumns will contain all columns that you are allowed to update via this request. For each of them check, whether there is a value in the request body or not. If yes, add it to the update statements, if not, ignore it (this assumes, the properties in the req.body and the columns in the table have the same name). Furthermore, to create a parameterized query, add the respective value to a values array, that you then can pass to the query.
If you don't have any values, there is nothing to do, so you can immediately return.
Else execute the query (don't forget to also add the cid to the values array). And return the respective status, based on whether there was an error or not.
BTW: 201 is status CREATED. You shouldn use that, if you are updating an already existing entity ...

Related

MySQL Node JS: select query results to array and use this array in other functions

I need to get user information and use it in all file but when i save it to array or session array - it show undefined.
connection.query('SELECT * FROM users WHERE username = ? OR email = ? AND password = ?', [login, login, password], function (err, results) {
if (results.length > 0) {
req.session.username = results[0].username;
req.session.email = results[0].email;
req.session.password = results[0].password;
req.session.premium = results[0].premium;
req.session.created_at = results[0].created_at;
} else {
console.log("Error!");
}
});
The arrays and sessions are always undefined...
req is a function variable/public variable I assume. connection.query is asynchronous. Callbacks are always asynchronous, and every REST API is.
Asynchronous basically allows the function callbacks to run together with the next lines of code.
The reason why req isn't being returned any value is because the req's value gets printed out first before it's actually being assigned within the function.
If you would like to add everything to req, either do sth like:
someFunctionYouHaveCreated: (req,res,type) => {
connection.query('SELECT * FROM users WHERE username = ? OR email = ? AND password = ?', [login, login, password], function (err, results) {
if (results.length > 0) {
req.session.username = results[0].username;
req.session.email = results[0].email;
req.session.password = results[0].password;
req.session.premium = results[0].premium;
req.session.created_at = results[0].created_at;
} else {
console.log("Error!");
}
DoSomething(req);
});
}
DoSomething: (req) => {
//Do something
}
Or, create a promise, and run the function based on promise. Use promise.all to assign value: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all, but I don't think you need such level of complexity.

How to execute a list of SQL commands sequentially?

I'm using MySQL for NodeJS and trying to do something like this:
dbQueries = ['multiple', 'sql', 'statements', 'that', 'need', 'to', 'be', 'executed', 'in', 'order'];
executedQueries = 0;
dbConn = mysql.connect();
maxQueries = dbQueries.length;
dbQueries.forEach(async (dbQuery) => {
console.log("Start");
return dbConn.query(dbQuery, function(err, results, fields) {
console.log("Finish");
if (err) {
errorList.push({ err, results, fields, dbQuery });
}
executedQueries++;
if (executedQueries >= maxQueries) {
if (errorList.length > 0) {
console.log("Error: ", databaseTable.name, " Errors reported: ", errorList);
}
if (typeof(callbackFunc) === 'function') { callbackFunc(errorList, executedQueries); }
}
});
});
But what ends up happening is that sometimes queries finish out of order. I know this because I setup the columns, then modify the table by adding in primary keys etc, and it sometimes errors with Table 'blah.blah' doesn't exist. The errors change each time. I could see this due to there being multiple Starts before seeing multiple Finishes. Not sure if I am using async correctly or not.
I do not want to turn on multipleStatements if possible.
The main reason you are seeing unexpected result is because nodejs executes these queries asynchronously. Correct way to run multiple queries:
dbQueries = ['multiple', 'sql', 'statements', 'that', 'need', 'to', 'be', 'executed', 'in', 'order'];
dbConn = mysql.connect();
function runQueries(dbQueriesArr) {
if(dbQueriesArr.length === 0)
return;
var dbQuery = dbQueriesArr[0];
dbConn.query(dbQuery, function(err, results, fields) {
if (err) {
errorList.push({ err, results, fields, dbQuery });
}
var dbQueriesArr_rest = dbQueriesArr.splice(1);
runQueries(dbQueriesArr_rest);
});
}
runQueries(dbQueries);

how to maintain group ID for bulk create in mysql

Below generate primary key auto-incremented but is there any way to assign or generate group id to those record which creates in one particular bulk using sequelize with MySQL.
or there is any way in mysql
here is my code
Model.bulkCreate(data,{individualHooks: true})
.then(function(result) {
console.log(result)
})
.catch(function(error){
console.log(error);
})
I did something like this,
first, I add the field with name groupId and then get groupid on every insertion and append with request bod.got time now so posting now :) might help some one else
tasks.max('groupId').then(function (maxid) {
var newbody = [];
for (var i = 0; i < req.body.length; i++) {
body.groupId = maxid + 1;
newbody.push(body);
}
tasks.bulkCreate(newbody, {individualHooks: true}).then(function (taskvalues) {
res.status(200).json(taskvalues);
}).catch(function (err) {
res.status(500).json(err);
})

TypeError: Cannot read property 'name' of undefined

When i type the username which is there in Table "fun" i am not facing any error but when i type wrong name that is the name which is not there in the table am facing error this is the error and code is attached below.
app.post('/Fu',function(req,res,next){
var username = req.body.uname;
var password = req.body.pwd;
con.query('SELECT name FROM fun WHERE name = "' + username +'" ',function(err, result,fields) {
var w = result[0].name;
if( username == w ){
console.log("login successful");
}
else{
console.log("login not successful");
}
}
});
res.send("success1");
});
can someone please help with the error.
This error is probably related to the fact that, when username is not present in the table, result will be set to and empty array []. That means that it has no elements at all, so result[0] is undefined.
Make sure to check for that before trying to get result[0].name.
Also, I would suggest you a few things:
1) Add error checking before anything else;
2) You do not need to check if the name is equal to the result. The query you wrote will only return entries that already match that requirement;
3) Send the responses inside the callback function, otherwise, the user will get the "success1" answer before the query has even finished executing.
Here follows the resulting code:
app.post('/Fu',function(req, res, next){
var username = req.body.uname;
var password = req.body.pwd;
con.query('SELECT name FROM fun WHERE name = "' + username +'"', function(err, result,fields) {
if (err) {
response.sendStatus(500);
return;
}
if (result.lenght > 0) {
res.send('Login was successful');
} else {
res.send('Login was not successful');
}
});
});
Your problem is here:
var w = result[0].name;
Because the result set at [0] doesn't exist (query came back with nothing). you are trying to get the name value from something that is undefined.
Do something like this:
var w
if (result[0]) {
w = result[0].name
} else {
//your logic to handle this scenario
}
That assumes that whatever db querying library you use will return an array, even if empty. If it returns undefined instead of an empty array, your if statement would need to look more like: if (result && result[0])

nodejs parse mysql row to object

I'm a little newbie in node.js + mysql + object oriented.
Following question here I would like the 'Content' object to use the values returned by a mysql query. What I'm doing now I find it is really redundant and possibly stupid as rows[0] itself is the object I want to use. Any better way for doing this? Or different approach if this is wrong also appreciated.
(I'm using binary uuid keys that must be hex-stringifyed again to send as resource response)
content.js:
function Content() {
this.id = '';
this.name = '';
this.domain = '';
}
Content.prototype.validate = function(path, queryParams) {
...
return true;
};
Content.prototype.whatever = function(apiVersion, params, callback) {
...
return callback(null, newParams);
};
mysql.js:
MySQLDb.SELECT_CONTENT_ID = "SELECT id, name, domain FROM content WHERE id = UNHEX(?)";
MySQLDb.prototype.findContentByID = function(id, callback) {
this.dbConnection.query(MySQLDb.SELECT_CONTENT_ID, [ id ],
function(err, rows, fields) {
var content = new Content();
if (rows.length > 0) {
var i = 0;
for (var key in rows[0]) {
if (rows[0].hasOwnProperty(key) && content.hasOwnProperty(key)) {
// BINARY(16) --> HEX string
if (fields[i].columnType === 254) {
content[key] = rows[0][key].toString('hex').toUpperCase();
} else {
content[key] = rows[0][key];
}
} else {
console.log('Column ' + key + ' out of sync on table "content"');
}
i += 1;
}
}
callback(err, content);
});
};
contentRes.js:
contentRes.GETWhatever = function(req, res) {
db.findContentByID(req.params.id, function onContent(err, content) {
if (err || !content.validate(req.path, req.query)) {
return res.send({});
}
content.whatever(req.query.apiVersion, req.query.d,
function onWhateverdone(err, params) {
if (err) {
return res.send({});
}
return res.send(params);
});
});
};
I think a lot of people would say you are doing it generally the right way even though it admittedly feels redundant.
It might feel a little cleaner if you refactored your code such that you could call the Content() constructor with an optional object, in this case rows[0] although if you were keeping it clean you wouldn't have access to the fields so you would take a different approach to the data type conversion - either by selecting the HEX representation in query or simply having your Content() know it needs to convert the id property.
Keeping it fairly simple (by which I mean ignoring making the constructor a bit more intelligent as well as any error detection or handling), you would have:
function Content(baseObj) {
this.id = (baseObj && baseObj.id) ? baseObj.id.toString('hex').toUpperCase() : '';
this.name = (baseObj && baseObj.name) ? baseObj.name : '';
this.domain = (baseObj && baseObj.domain) ? baseObj.domain : '';
}
Then you could do something like this:
MySQLDb.prototype.findContentByID = function(id, callback) {
this.dbConnection.query(MySQLDb.SELECT_CONTENT_ID, [ id ],
function(err, rows, fields) {
if (err) return callback(err,null);
return callback(err, new Content(rows[0]));
});
You 'could' also grab the rows[0] object directly, HEX the UUID more or less in situ and modify the __proto__ of the object, or under Harmony/ES6 use the setPrototypeOf() method.
MySQLDb.prototype.findContentByID = function(id, callback) {
this.dbConnection.query(MySQLDb.SELECT_CONTENT_ID, [ id ],
function(err, rows, fields) {
if (err) return callback(err,null);
var content = rows[0];
content.id = content.id.toString('hex').toUpperCase();
content.__proto__ = Content.prototype;
return callback(err, content);
});
Note, I said you 'could' do this. Reasonable people can differ on whether you 'should' do this. __proto__ is deprecated (although it works just fine in Node from what I have seen). If you take this general approach, I would probably suggest using setPrototypeOf(), and install a polyfill until you are otherwise running with ES6.
Just trying to give you a couple of other more terse ways to do this, given that I think the redundancy/verbosity of the first version is what you didn't like. Hope it helps.