Undefined push to array - Basic Application using ExpressJs and MySQL - mysql

First of all, I have to tell you I'm pretty noob in this "universe". I'm using: ExpressJs, MySql, Body-Parser, Express-session, Ejs template for creating an Basic Contacts Application in Node.
My database is composed from 3 tables:
user (user_id, first, second name, username, password)
contacts (ct_id, first, second name, phone numb.)
user_contacts (user_id, ct_id) --> foreign keys for user and contacts
I want to listing on /myProfile page all details about user and his contacts.
I don't know how to handle the select queries.
So, after some documentation I did this:
conn.query('SELECT * FROM user_contacts WHERE user_id= ?', req.session.user_id, function (err, result) {
if(err) throw err;
console.log(result);
var queryArray = "";
for(var i = 0; i < result.length; i++){
queryArray += `SELECT * FROM contacts WHERE ct_id= ${result[i].ct_id}; `;
}
console.log(queryArray);
conn.query(queryArray, function (err, result) {
if(err) throw err;
console.log(result);
res.render('myProfile/contacts', {
title: `${req.session.user_nickname}'s Contacts`,
data: result
});
});
});
But I have an error
ER_PARSE_ERROR: You have an error in your SQL syntax;
..when queryArray.length > 1
I searched and it's something about Multiple statement queries but I dont know how to solve it.
Edit 2:
I modify my code..
conn.query('SELECT * FROM user_contacts WHERE user_id= ?', req.session.user_id, function (err, result) {
if(err) throw err;
var datas = [];
for(var i = 0; i < result.length; i++){
getContacts = function(query){
conn.query(query, function (err, result) {
console.log('Creating data');
data = {
user: req.session.user_nickname,
contact:{
ct_firstName: result[0].ct_firstName,
ct_SecondName: result[0].ct_SecondName,
ct_PhoneNumber: result[0].ct_PhoneNumber
}
}
return data;
});
}
console.log('Send data to array');
datas.push(getContacts(`SELECT * FROM contacts WHERE ct_id = ${result[i].ct_id}`));
}
console.log(datas); // [ undefined, undefined ]
res.render('myProfile/contacts',{
title: `${req.session.user_nickname}'s profile`,
data: datas
})
});
But now my array contain undefined objects?? Any solution?
Maybe is something about scope?
My result:
Send data to array
Send data to array
[ undefined, undefined ]
Creating data
Creating data
I push the object to array before creating it. How is it possible?

1797,
I noticed you have several small queries grabbing the contact info for a given user. You could simplify your code by combining your queries into a single one. Often times 1 big query is more efficient (plus it's easier to maintain). I'm using a join. More info here.
const contacts = [];
const query = "
SELECT c.*
FROM user_contact uc
JOIN contact c ON uc.contact_id = c.contact_id
WHERE uc.user_id = ?
GROUP BY c.contact_id
";
conn.query(query, req.session.user_id, (err, results) => {
if (err) throw new Error(err);
// it seems that this could just be 'contacts = results' since they
// have the same structure
contacts = results.map(result => {
return {
ct_firstName: result[0].ct_firstName,
ct_SecondName: result[0].ct_SecondName,
ct_PhoneNumber: result[0].ct_PhoneNumber
};
});
res.render('myProfile/contacts',{
title: `${req.session.user_nickname}'s profile`,
data: contacts
});
});

Related

Node and Axios - How to make sequentials requests

I need to make 2 requests to my API to insert data in 2 different table:
Workflow:
request to get the last id + 1 => create the array I need (last_id, values) => two INSERT in MySql, 1st with varius data, 2nd with the array I created.
router.post("/addentry", function (req, res) {
let sql = "SELECT MAX(id) + 1 AS last_id FROM entries;"; // I get the id
let query = connection
.query(sql, (err, results) => {
if (err) throw err;
res.header("Access-Control-Allow-Origin", "*");
// put the id in a variable
var last_id = results[0].last_id;
var categoriesMap = req.body.categories;
var valCat = Object.values(categoriesMap);
// I create the array with other data
var catArray = valCat.map((item) => {
return [last_id, item];
});
})
.then((catArray) => {
let sql = `BEGIN; INSERT INTO entries (title,kindof) VALUES("${[
req.body.title,
]}","${req.body.kindof}");
INSERT INTO categories_main (entry_id, cat_id) VALUES ? ;
COMMIT;`;
let query = connection.query(sql, [catArray], (err, results) => {
if (err) throw err;
console.log(results);
res.header("Access-Control-Allow-Origin", "*");
res.send("Entry added to DB");
});
});
The first part works perfectly but with the second I get
TypeError: connection.query(...).then is not a function
Any idea how to do it?
Thanks
First things first, you should make sure that you use node-mysql2 instead of node-mysql. node-mysql2 has a built in functionality that helps making multiple queries inside a single connection. I have provided you this answer that exemplifies how to use it properly.
Moving forward, after you've done that, to be able to work with your result object, you will need JSON.
The following syntax is what you probably want to use:
var stringify = JSON.parse(JSON.stringify(results[0]));
for (var i = 0; i < stringify.length; i++) {
var last_id = stringify[i]["last_id"];
}
I need to make 2 requests to my API to insert data in 2 different table:
From code, I see that you are intending to do a single API call to the server and run 2 queries.
You can do .then only on a Promise, so as we can see connection.query is not returning a Promise and hence not then able.
Also you are setting response headers multiple times res.header("Access-Control-Allow-Origin", "*"); do this only once in a request cycle. So lets follow the callback approach instead of then.
let sql = "SELECT MAX(id) + 1 AS last_id FROM entries;"; // I get the id
let query = connection
.query(sql, (err, results) => {
if (err) {
res.header("Access-Control-Allow-Origin", "*");
return res.status(500).send({error:'server error'});
}
// put the id in a variable
var last_id = results[0].last_id;
var categoriesMap = req.body.categories;
var valCat = Object.values(categoriesMap);
// I create the array with other data
var catArray = valCat.map((item) => {
return [last_id, item];
});
let sql = `BEGIN; INSERT INTO entries (title,kindof) VALUES("${[
req.body.title,
]}","${req.body.kindof}");
INSERT INTO categories_main (entry_id, cat_id) VALUES ? ;
COMMIT;`;
let query = connection.query(sql, [catArray], (err, results) => {
if (err) {
res.header("Access-Control-Allow-Origin", "*");
return res.status(500).send({error:'server error'});
}
console.log(results);
res.header("Access-Control-Allow-Origin", "*");
res.send("Entry added to DB");
});
})
Here the complete solution, starting from what #SubinSebastian advised to me.
First of all I needed node-mysql2, that alows promises and therefore chained requests.
And then:
router.post("/addentry", function (req, res) {
let sql = "SELECT MAX(id) + 1 AS last_id FROM entries;";
connection.promise().query(sql)
.then((results) => {
// I get the value from results
var stringify = JSON.parse(JSON.stringify(results[0]));
for (var i = 0; i < stringify.length; i++) {
console.log(stringify[i]["last_id"]);
var last_id = stringify[i]["last_id"];
}
// I get some parameters and I create the array
var categoriesMap = req.body.categories;
var valCat = Object.values(categoriesMap);
var catArray = valCat.map((item) => {
return [last_id, item];
});
let sql = `BEGIN; INSERT INTO entries (title,kindof) VALUES("${[
req.body.title,
]}","${req.body.kindof}");
INSERT INTO categories_main (entry_id, cat_id) VALUES ? ;
COMMIT;`;
// array as second query parameter
let query = connection.query(sql, [catArray], (err,results) => {
if (err) throw err;
});
})
.catch(console.log);

How to return the response of Node.js mysql query connection

I am new at Node.js and I want to find something from database by using select query.
Here is my code.
var address = socket.request.client._peername.address;
var ip_addrss = address.split("::ffff:");
let mine = ip_addrss[1];
var location = iplocation_find(mine);
connection.connect( function () {
// insert user data with IP, location --- has got a status.
let stranger = "";
var values = [];
if (mine == null){
mine = "local server";
}
values.push(mine);
values.push('location');
var sql = "INSERT INTO user_list (IP_address, location) VALUES (?)";
connection.query(sql, [values], function (err, res){
if (err) throw err;
});
// control chatting connection between users
connection.query("SELECT IP_address FROM user_list WHERE status = ? AND location = ?", [0, "location"], function (err, res){
if (err) throw err;
stranger = res[0].IP_address;
console.log(stranger);
});
var room_users = [];
room_users.push(mine);
room_users.push(stranger);
console.log(room_users);
connection.query("INSERT INTO chatting_status (IP_client_1, IP_client_2) VALUES (?)", [room_users], function (err, res){
if (err) throw err;
console.log('inserted');
});
});
Now the problem is "stranger". It is not working anymore. Just always null.
Please tell me how I can return value in mysql query statement.
on my console, shows this.
[ 'local server', '' ]
127.0.0.1
inserted
[ '192.168.1.100', '' ]
127.0.0.1
inserted
Above, 'local server' and '192.168.1.100' are values of mine. And also '127.0.0.1' is the value of stranger only in query. But out of query it is just null.
You are using asynchronous operations with your .connect() and .query() calls. To sequence code with asynchronous callbacks like this, you have to continue the flow of control inside the callback and then communicate back errors or result via a callback.
You could do that like this:
let address = socket.request.client._peername.address;
let ip_addrss = address.split("::ffff:");
let mine = ip_addrss[1];
let location = iplocation_find(mine);
function run(callback) {
connection.connect( function () {
// insert user data with IP, location --- has got a status.
let values = [];
if (mine == null){
mine = "local server";
}
values.push(mine);
values.push('location');
var sql = "INSERT INTO user_list (IP_address, location) VALUES (?)";
connection.query(sql, [values], function (err, res){
if (err) return callback(err);
// control chatting connection between users
connection.query("SELECT IP_address FROM user_list WHERE status = ? AND location = ?", [0, "location"], function (err, res){
if (err) return callback(err);
let stranger = res[0].IP_address;
console.log(stranger);
let room_users = [];
room_users.push(mine);
room_users.push(stranger);
console.log(room_users);
connection.query("INSERT INTO chatting_status (IP_client_1, IP_client_2) VALUES (?)", [room_users], function (err, res){
if (err) return callback(err);
console.log('inserted');
callback(null, {stranger: stranger, room_users: room_users});
});
});
});
});
}
run((err, result) => {
if (err) {
console.error(err);
} else {
console.log(result);
}
});
Personally, this continually nesting callback code is a drawback of writing sequenced asynchronous code with plain callbacks. I would prefer to use the promise interface to your database and write promise-based code using async/await which will allow you to write more linear looking code.

nodejs mysql queries showing only one records instead of all records in the database

Am trying to retrieve all the database records from a table called post using node js but the problem is that only one record is retrieved instead of all.
In php I can use while() loop to loop through the database record to get all data.
Currently, I do not know how to neatly loop through the database in nodejs to get all the records from database. Some Stackoverflow scholars suggest using await/async method but i do not know to to implement it on the code below to make it work. can someone help me fix the issue.
var connection = require('./config');
module.exports.getpost = function (req, res) {
connection.query('SELECT * FROM posts', function (error, results, fields) {
if (error) {
console.log('error');
res.json({
status : false,
message : 'there are some error with the query'
});
} else {
var postid = results[0].id;
var title = results[0].title;
var content = results[0].content;
var type = -1;
console.log(title);
// Checking user status
connection.query('SELECT count(*) as cntStatus,type FROM like_table WHERE userid= ? and postid=?', [userid,postid], function (error, results, fields) {
if (error) {
console.log('error');
res.json({
status : false,
message : 'there are some error with the query'
});
} else {
var total_count = results[0].cntStatus;
if(total_count > 0){
type = results[0].type;
}
var total_count = results[0].cntStatus;
var result = {
"id" : postid,
"title" : title,
"content" : content,
"type" : type,
"likes" : total_count
};
console.log('query okay');
res.json({
//data:results,
data : result
});
}
});
}
});
}
I'm assuming you're using mysql npm. In that case I'm not sure what is the problem in your case. Results param is an array of rows returned by your select statement. So you can use loop to iterate trough all the rows.
You don't actually need to use async/await (which doesn't have any advantage in terms of functionality but looks cleaner). But if you want to get rid of callbacks you need to wrap connection query into a promise or use mysql2 npm which has promise interface. Here is how you can iterate trough all the rows from your select using async/await instead of callback:
var connection = require('./config');
module.exports.getpost = async function (req, res) {
try {
const queryResult = await query('SELECT * FROM posts');
queryResult.forEach(row => {
console.log(row.title);
})
} catch (err) {
console.log('error');
res.json({
status: false,
message: 'there are some error with the query'
});
}
}
Please note that you need to use nodejs 8 to run the code with async/await.
Also you don't need to do another query inside of your posts query, you can merge those two using SQL join
async waterfall - Runs an array of functions in series, each passing their results to the next in the array. However, if any of the functions pass an error to the callback, the next function is not executed and the main callback is immediately called with the error.
var connection = require('./config');
var async = require('async');
module.exports.getpost = function (req, res) {
var arrayOfFuncs = [];
var func_1 = function(callback) {
connection.query('SELECT * FROM posts', function (error, results, fields) {
if (error) {
console.log('error');
callback(error, null);
} else {
var toPass = {};
toPass.postid = results[0].id;
toPass.title = results[0].title;
toPass.content = results[0].content;
toPass.type = -1;
callback(null, toPass);
}
})
}
arrayOfFuncs.push(func_1);
var func_2 = function(prevData, callback) {
connection.query('SELECT count(*) as cntStatus,type FROM like_table WHERE userid= ? and postid=?', [userid,prevData.postid], function (error, results, fields) {
if (error) {
console.log('error');
callback(error, null);
} else {
var total_count = results[0].cntStatus;
if(total_count > 0){
type = results[0].type;
}
var total_count = results[0].cntStatus;
var result = {
"id" : postid,
"title" : title,
"content" : content,
"type" : type,
"likes" : total_count
};
console.log('query okay');
callback(null, result);
}
});
}
arrayOfFuncs.push(func_2);
async.waterfall(arrayOfFuncs, function(errString, finalResult) {
if(errString) {
return res.send(errString);
} else {
return res.send(finalResult);
}
});
}

ID being passed in as a parameter, query failing to return a row that actually exists

I'm using node-mysql trying to query the familiar Northwind database which I have locally. Here is my Customer model:
models/customer.js
var connection = require('../../database/connection');
var Customer = {
list: function(cb) {
var q = 'select CustomerID, ContactName from Customers limit 10';
return connection.query(q, cb);
},
read: function(id, cb) {
var q = 'select * from Customers where CustomerID = ' + id;
return connection.query(q, cb);
}
};
module.exports = Customer;
Alright, I know those kinds of queries are vulnerable to SQL injection but I'm coming from MongoDB and right now I'm experimenting to see that I can get my MySQL connections and queries to work before I refactor them for security. So here's how I call them from a controller:
controllers/customers.js
var Customer = require('../models/customer');
var CustomersController = {
index: function(req, res, next) {
var data = {};
Customer.list(function(err, rows) {
if (err) {
next(new Error('No customers found!'));
return;
}
data.title = 'All customers';
data.customers = rows;
res.render('customers/index', data);
});
},
view: function(req, res, next) {
var id = req.params.id;
var data = {};
Customer.read(id, function(err, row) {
if (err) {
next(new Error('The customer with ID ' + id + ' does not exist!'));
return;
}
data.title = row.ContactName;
data.customer = row;
res.render('customers/read', data);
});
}
};
module.exports = CustomersController;
Finally, the routes:
var router = require('express').Router();
var CustomersController = require('../../app/controllers/customers');
router.route('/customers')
.get(CustomersController.index)
router.route('/customers/:id')
.get(CustomersController.view)
module.exports = router;
GET /customers is working but GET /customers/:id does not. For example, if I want to view the details for the customer with id ALFKI, I get the error I threw in the controller -- "The customer with ID ALFKI does not exist!" yet when I directly query the database with the same query I used in my model, i.e select * from Customers where CustomerID = 'ALFKI', a row is returned.
Perhaps a fresh pair of eyes can tell me what I'm doing wrong?

MySQL Nesting Relations

I use backbone and need to nest Answers in Questions and Questions in Categories.
My problem is the data I get from MySQL.
I would like to have an array I can easily use with backbone, starting at the top (Category) and nest down to the bottom (Answers).
[Category1: [Question1: [Answer1: {...} ] ] ]
I use the following query to get all my MySQL data:
var getRecord = function(callback) {
var options = {
sql: 'SELECT * FROM Categories ' +
'LEFT JOIN Questions ON Categories.idCategories = Questions.idCategory ' +
'LEFT JOIN Answers ON Questions.idQuestions = Answers.idQuestion ',
nestTables: true
}
req.app.sql.query(options, function(err, result) {
if (err)
return callback(err, null)
outcome.record = result
return callback(null, 'done')
})
}
And the output looks something like this:
[
0: [CategoryObj, QuestionObj, AnswerObj]
1: ...
]
The MySQL Node Package does not nest 1:n relations, instead it creates an array with the length of most matches, so in the case I have 2 Categories, with each two Questions, with each two Answers -> Array length of 8, because I have 8 Answers in total.
But I cannot nest this array, in backbone collections without writing crazy loops and hacks.
Am I doing something wrong in the query or is there a packages that does the parsing job?
(I'm used to MongoDB (using embedded documents was quite easy) and now I have to use MySQL for this project..)
This is the MySQL Node Package on npm
There is nothing wrong with the package or how you use it. It just gives you the results returned by MySQL. As you probably know, MySQL itself does not format its results in a "nested" way when you're dealing with 1:n relations. If you use JOINs, it will give you a table with a row for each result it found. As it's a "table-formated" result, all rows have the same number of cells.
You can try to see the result of your request in PHPmyAdmin for example.
Thus, you have to post-format the results. There are probably modules to do that, but I have never used one yet.
If you want to do it yourself, you could do something like :
var nestedResult = {};
result.forEach(function(val){
var category = val[0],
question = val[1],
answer = val[2];
if (!nestedResult[category]){
nestedResult[category] = {};
}
if (!nestedResult[category][question]){
nestedResult[category][question] = [];
}
nestedResult[category][question].push(answer);
});
Which will give you something like :
{
"mysql" : {
"what is JOIN" : ["answer 1 blabla....","answer 2 blabla"],
"innoDB vs MyISAM" : ["answer 1","answer 2"]
},
"php" : {
"why no php 6 ?" : ["answeeeerr"]
}
}
I ended up parsing it myself. For some reason I was not able to find a well working ORM helper, that could do this job for me. Anyway I tried to avoid this solution, but here you go if you have the same problem one day this might help.
var async = require('async')
var getAnswers = function (id, callback) {
req.app.sql.query('SELECT * FROM Answers WHERE idQuestion LIKE ?', [id], function(err, result) {
if (err)
return callback(err, null)
return callback(null, result)
})
}
var getQuestions = function (id, callback) {
req.app.sql.query('SELECT * FROM Questions WHERE idCategory LIKE ?', [id], function(err, result) {
if (err)
return callback(err, null)
// Pair answers to questions
async.times(result.length, function(n, next) {
getAnswers(result[n].idQuestions, function (err, answers) {
result[n].answers = answers
next(err, result[n])
})
}, function(err, questions) {
callback(null, questions)
})
})
}
var getRecord = function(callback) {
req.app.sql.query('SELECT * FROM Categories', function(err, result) {
if (err)
return callback(err, null)
// Pair questions to categories
async.times(result.length, function(n, next) {
getQuestions(result[n].idCategories, function (err, questions) {
result[n].questions = questions
next(err, result[n])
})
}, function(err, final) {
callback(null, final)
})
})
}
var asyncFinally = function(err, results) {
if (err)
return next(err)
// we call results[0] because async.times leaves all the categories in there..
// sendSomewhere( results[0] )
}
async.parallel([getRecord], asyncFinally)