SQl-queries run twice in Heroku NodeJS - node.js

Currently I have deployed my website on Heroku with NodeJS.
I came across a weird problem: some SQL-queries are executed twice on mobile, while I don't have this problem on any desktop. So to test if this really was the case, I did a console.log after every database query. In the heroku log I saw that SQL-queries via my mobile were executed twice.
As you can see below, the request is about if you already follow someone. This request has a lot of nested SQL-queries. I don't really know how to properly structure it and therefore it is possible that the problem lies within that. A string is returned which says something about the new relation between you and the user you're trying to follow/unfollow.
So what I'm trying to do:
Check if you follow the person. If this is the case, unfollow the user. Return.
Then, check if the user has a public or private account. If he/she has a public account, you can directly follow the person. Return.
After that, check if you already try to follow the user with a lock. If this is the case, remove the request. Return.
If (3) is not the case, make a request. Return.
When I make this request on my computer, I looked at the heroku logs which showed the following:
2018-03-31T18:13:18.182665+00:00 app[web.1]: execution 1
2018-03-31T18:13:18.203767+00:00 app[web.1]: execution 3
2018-03-31T18:13:18.204511+00:00 app[web.1]: POST /user/follow 200 55.619 ms - 8
2018-03-31T18:13:18.227543+00:00 app[web.1]: execution 4
However, when I did the exact same thing on my mobile, this was showed:
2018-03-31T18:16:24.776125+00:00 app[web.1]: execution 1
2018-03-31T18:16:24.786991+00:00 app[web.1]: execution 1
2018-03-31T18:16:24.793902+00:00 app[web.1]: execution 3
2018-03-31T18:16:24.794795+00:00 app[web.1]: POST /user/follow 200 54.334 ms - 8
2018-03-31T18:16:24.802526+00:00 app[web.1]: execution 3
2018-03-31T18:16:24.803279+00:00 app[web.1]: POST /user/follow 200 46.972 ms - 8
2018-03-31T18:16:24.816062+00:00 app[web.1]: execution 4
2018-03-31T18:16:24.821743+00:00 app[web.1]: execution 4
To make it clear which SQL-statement executed, I made a console.log for each of them with a different name. ('execution1', 'execution2', etc.).
// Check the relationship between the user and the search-user
router.post('/follow', function(req, res, next) {
// Check if the user is logged in
if (!req.session.user) {
return;
}
// Create connection with database
pool.getConnection(function (err, database) {
if (err) throw err;
// Check if you already follow the user
var sql = "SELECT * FROM Followers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 1");
if (err) throw err;
// You follow the user if the if-statement is true
if (result.length != 0) {
// Unfollow the person
var sql = "DELETE FROM Followers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 2");
if (err) throw err;
database.release();
});
return res.send("FOLLOW");
};
// Check if the person has a lock on its account
var sql = "SELECT private FROM Users WHERE user = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 3");
if (err) throw err;
// If the account is public, then the if-statement below is true
if (result[0].private == "0") {
// Follow if the account is not private
var sql = "INSERT INTO Followers (user, following) VALUES (" + mysql.escape(req.session.user) + ", " + mysql.escape(req.session.userSearch) + ")";
database.query(sql, function(err, result, fields) {
console.log("execution 4");
if (err) throw err;
database.release();
});
return res.send("UNFOLLOW");
}
// Prepare data
var sql = "SELECT * FROM PendingFollowers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 5");
if (err) throw err;
// Check if you already try to follow the person
if (result.length == "1") {
// Remove the request
var sql = "DELETE FROM PendingFollowers WHERE user = " + mysql.escape(req.session.user) + " AND following = " + mysql.escape(req.session.userSearch);
database.query(sql, function(err, result, fields) {
console.log("execution 6");
if (err) throw err;
database.release();
});
return res.send("FOLLOW");
}
// Follow and put it in pending
var sql = "INSERT INTO PendingFollowers (user, following) VALUES (" + mysql.escape(req.session.user) + ", " + mysql.escape(req.session.userSearch) + ")";
database.query(sql, function(err, result, fields) {
console.log("execution 7");
if (err) throw err;
database.release();
return res.send("REQUESTED");
});
});
});
})
});
});
EDIT:
HTML:
<button class="buttonFollow" ng-click="follow()"> {{ status }} </button>
AngularJS:
// Status follower
$http.get('/user/status').
then(function(res) {
$scope.status = res.data;
});
// Follow someone
$scope.follow = function() {
$http.post('/user/follow').
then(function(res) {
$scope.status = res.data;
$http.get('/user/informationFollower').
then(function(res){
$scope.following = res.data[0].following;
$scope.followers = res.data[0].followers;
});
});
};
The HTML/AngularJS above is from the page of the user you want to follow. So when the follow-request is done, the number of followers/following of the targeted user will be updated. When I try to follow someone via my computer, the number is incremented with 1 (which is OK). But via my phone, it is incremented with 2. It created a duplicate follow-row in my database on table Followers, but the id is not the same.

Related

asynchronous behavior of nodejs

I am new to node.js and I try to render different pages based on some conditions, however, I sometimes meet the problem "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client", I think this is because of the asynchronous behavior of node.js. How can I fix this problem?
I tried setTimeout but I think that's not the right way to do that.
The following part is the section where I met this issue:
/*
signup err code:
0 stand for no errors,
1 stand for confirmPassword and password not match
2 stand for user already exist
*/
app.post('/signup',(req, res) => {
//initialize the signupErr to be 0
signupErr = 0;
//get the data from the post request
let username = req.body.username;
let email = req.body.email;
let password = req.body.password;
let confirmPassword = req.body.confirmPassword;
let organization = req.body.organization;
/*first check the twice entered password, if not match set error number to 1 for the server to render the corresponding error message*/
if (password!=confirmPassword){
signupErr = 1;
res.redirect('/signup');
}
//form the query to consult the database to check if user exists
let queryUsername = "SELECT password FROM User WHERE Username = " + "'" + username + "'";
let queryEmail = "SELECT email FROM User WHERE Email = " + "'" + email + "'";
// check if username exists
connection.query(queryEmail,(err,results) => {
if(err){
console.log("Errore login: " + err);
} else if(results.length!=0) {
signupErr = 2;
res.redirect('/signup');
}
});
//check if email exists
connection.query(queryUsername,(err,results) => {
if(err){
console.log("Errore login: " + err);
} else if(results.length!=0) {
signupErr = 2;
res.redirect('/signup');
}
});
// form the insertion query if no err found
let queryInsert = "INSERT INTO `PIA`.`User` (`Username`, `Email`, `Password`,`Organization`) VALUES ('"+username +"', '"+ email +"', '"+password +"', '"+organization + "')";
// insert the data into the database
connection.query(queryInsert,(err,results) => {
if(err){
console.log("Errore login: " + err);
} else{
console.log("Inserted");
res.render('main');
}
});
});
The insertion part will still run sometime after the redirect.
I'll be really grateful if you can give me any ideas on how to solve that.

How to get a string from query result in Nodejs

My code is in Nodejs backend below
app.get('/room_selected', function (req, res){
var clientID = 'a#gmail.com';
var room = 'Room 1';
var query = connection.query ('SELECT clientID FROM clientDevices WHERE deviceName = ?', [room],
function (err, rows, fields){
if (err) throw err;
return rows[0].clientID;
});
console.log (query);
if (clientID == query){
res.status(400).json ('success');
} else {
res.status(400).json('The selected room does not have a device attached');
}
});
When I print console.log(query), it returns [ { clientID: 'a#gmail.com' } ].
I want to return only a#gmail.com. Could you guys know how to figure out it? since I want it to compare with clientID to print out the success message, however, it printed out The selected room does not have a device attached
Please help. Thank you
In your code, you didn't wait for the query to be executed. Following is the code which will give a response only after the query is executed.
And also success should not have a status code of 400 so I have removed that which will give a status code of 200
app.get('/room_selected', function (req, res){
var clientID = 'a#gmail.com';
var room = 'Room 1';
var query = connection.query ('SELECT clientID FROM clientDevices WHERE deviceName = ?', [room],
function (err, rows, fields){
if (err) throw err;
if (rows.length && clientID == rows[0].clientID){
res.json('success');
} else {
res.status(400).json('The selected room does not have a device attached');
}
});
});

Node.js - TypeError: Cannot read property 'length' of undefined

I am connecting Node.js to Android App.
And when I run 'npm start' the error(TypeError: Cannot read property 'length' of undefined) occurs.
It seems like it doesn't receive 'rows' property(the number of rows) from MySQL.
router.get('/:phone', function(req, res, next){
var phone = req.params.phone;
var sql = "SELECT * FROM bestfood_member WHERE phone = ? LIMIT 1;";
console.log("sql : "+ sql);
db.get().query(sql, phone, function (err, rows){
console.log("rows : " + JSON.stringify(rows));
console.log("row.length : " + rows.length);
if(rows.length > 0){
res.json(rows[0]);
} else {
res.sendStatus(400);
}
});
});
What is the problem?
Your SQL query probably errored. You need to check if the query was successfully executed.
if (err) throw err;
You may use these lines of code. rowCount will tell you how many rows do you have. I have also find out this solution after couple of days.
db.get().query(sql, phone, function (err, rows){
console.log("rows : " + JSON.stringify(rows));
console.log("rows.rowCount : " + rows.rowCount);

Correct way to get a value from mongodb?

I am using mongodb and mysql with my nodejs.
employee.find({status:1}, function(error,response) {
for(i=0;i<=response.length;i++){
var fileid = response[i]._id;
var sql = "SELECT * FROM EMPLOYEE WHERE `id` = '"+fileid+"'";
con.query(sql, function (err, result) {
if (err) throw err;
console.log("Result: " + result);
});
}
})
The above code gives me the exact record and result but in my logger file i am getting the below error everytime,But i have no problem in getting my output.I am using winston to record my service logs. The main reason why i am worrying about this error is my node js APi's are going down more or less after every 8 hours and my databases are not going idle(using forever npm module to run my service forever) and so i am believing that this might be the reason for killing my node processess. Below is my error.Any help?
"stack":["TypeError: Cannot read property '_id' of undefined"(var fileid = response[i]._id;)]
Because i should be less than response.length. array length is always greater than the last index.
For example,
var arr = [1,2]; //length is 2 and last index value is 1
Change you code like this: for(i=0;i<response.length;i++)
employee.find({status:1}, function(error,response) {
for(i=0;i<response.length;i++){
var fileid = response[i]._id;
var sql = "SELECT * FROM EMPLOYEE WHERE `id` = '"+fileid+"'";
con.query(sql, function (err, result) {
if (err) throw err;
console.log("Result: " + result);
});
}
})

How to query azure SQL from node.js server

I'm having some trouble with querying my DB on azure sql (I am very new to sql). I'm following the steps on https://learn.microsoft.com/en-us/azure/sql-database/sql-database-connect-query-nodejs, but it only includes tutorial steps on how to read tables, not manipulate them. I am trying to do INSERT and DELETE requests on my Node.js server, but I am getting a request error in one of the node modules, which makes me think that I'm going about requesting the operations wrong.
Here's some code:
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
// Create connection to database
var config =
{
userName: 'user_name',
password: 'password',
server: 'server_name',
options:
{
database: '_dbname'
, encrypt: true
}
}
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function (err) {
if (err) {
console.log(err)
}
else {
queryDatabase();
}
}
//this works fine, it's for initially loading the data from the database
function queryDatabase() {
console.log('\nReading rows from the Table...');
let obj = {};
let objs = [];
let request;
// Read all rows from table
request = new Request(
"SELECT * FROM [dbo].[TABLE_NAME]",
function (err, rowCount, rows) {
console.log('-- Done');
}
);
//this is for when an admin adds content to the app, SQL table not changing,
//node.js throws error
socket.on('add item', item => {
let index = getCollectionIndexById(item.id);
collections[index].items.push(item.item);
io.sockets.emit('add item', item);
request = new Request(`INSERT INTO [dbo].[TABLE_NAME](Id, attr1, attr2, attr3, attr4)
VALUES (`
+ item.id + ','
+ item.item.attr2 + ','
+ item.item.attr3 + ','
+ item.item.attr4 + ','
+ null, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to insert item');
});
connection.execSql(request);
console.log('> item sent to app');
});
//for when the admin removes content from the app, same error
socket.on('rm item', item => {
collections[getCollectionIndexById(item.id)].items.splice(item.index, 1);
io.sockets.emit('rm item', { "id": item.id, index: item.index });
request = new Request(`DELETE FROM [dbo].[TABLE_NAME] WHERE Id= `
+ item.id + ` AND attr1= ` + item.item.attr1, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to remove item')
});
connection.execSql(request);
console.log('> sent request to remove item');
});
The exact error msg is RequestError: Incorrect syntax near 'esse'., and its in one of the node modules called tedious in request.js.
So in summary, if anyone knows of a way to query Azure SQL Db's to make inserts and deletes, any help is appreciated!
You missed ) in the 'insert' SQL. Also, you'd need to set string value with single quotes of course.
Change the following lines of code
request = new Request(`INSERT INTO [dbo].[TABLE_NAME](Id, attr1, attr2, attr3, attr4)
VALUES (`
+ item.id + ','
+ item.item.attr2 + ','
+ item.item.attr3 + ','
+ item.item.attr4 + ','
+ null, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to insert item');
});
connection.execSql(request);
to
request = new Request(`INSERT INTO [dbo].[TABLE_NAME](Id, attr1, attr2, attr3, attr4) VALUES ('${item.id}', '${item.item.attr2}', '${item.item.attr3}', '${item.item.attr4}' null)`, function (err, rowCount, rows) {
if (err) throw err;
console.log('> requested db to insert item');
});
connection.execSql(request);
You will find an example here of how to INSERT records on a table using NodeJs and queryRaw.
conn.queryRaw("INSERT SalesLT.Product (Name, ProductNumber, StandardCost, ListPrice, SellStartDate) OUTPUT INSERTED.ProductID VALUES ('SQL Server Express 102', 'SQLEXPRESS 102', 0, 0, CURRENT_TIMESTAMP)", function (err, results)
You can use queryRaw also to DELETE records on a table.
Hope this helps.

Resources