Stored Procedure Output in NodeJS - mysql

Can someone tell me what is wrong with this code? I am getting syntax error near Select category_ID;
I am using latest version is mysql in nodejs
Note - If i remove the output params, Input code is properly working.
Node Server Code -
app.post('/api/createcategory', function (req, res) {
name = req.body.categoryName, icon = req.body.categoryIcon;
let createcategory = `CALL spAddCategory(?, ?, #category_id); SELECT #category_id;`
db.query(createcategory, [name, icon], (err, result) => {
if(err) {throw err};
console.log(result);
})
res.send('Category Created')
})
SQL Query -
CREATE PROCEDURE spAddCategory ( IN category_name varchar(255), IN category_icon varchar(255), OUT category_id int )
BEGIN
INSERT INTO categories ( categoryName, categoryIcon )
VALUES ( category_name, category_icon );
SELECT categoryID INTO category_id FROM categories
WHERE categoryName = category_name;
END

Instead of OUT-variables (which are useful mainly between procedures), consider handling the output as normal result set:
app.post('/api/createcategory', function (req, res) {
name = req.body.categoryName, icon = req.body.categoryIcon;
let createcategory = `CALL spAddCategory(?, ?);`
db.query(createcategory, [name, icon], (err, result) => {
if(err) {throw err};
console.log(result[0]);
})
res.send('Category Created')
})
And the procedure, returns the result set which contains the last inserted id (assuming the categoryID is an AUTO_INCREMENT id):
CREATE PROCEDURE spAddCategory (
category_name varchar(255),
category_icon varchar(255)
)
BEGIN
INSERT INTO categories ( categoryName, categoryIcon )
VALUES ( category_name, category_icon );
SELECT last_insert_id();
END
Note that you may end up with more than one category with same name.

Related

Check IF Result from Select Query with Async NodejS in MySQL?

I've got the following code in NodeJS using an Async/Promises wrapper for Mysql ;
row_c = await db.query( 'SELECT tagid FROM tags WHERE tagname = ?', [tag1] );
How do I now check if there is a result for an IF statement?
I tried;
if (row_c.tagid){
///some code
}
But it's not picking up the conditional. How do I check if the query returned a row?
db.query returns an array of rows. You can do the following:
row_c = await db.query( 'SELECT tagid FROM tags WHERE tagname = ?', [tag1] );
if (row_c.length) {
// if data is returned
console.log(row_c);
}

How to insert some table information to another table column?

I am a beginner in mySQL and I am trying to create a user's table with information about the user (see code) and populate a column with details that I get from a new table that gets created.
Now I want to be able to put some information from the 'creditcards' table like number for example, to the 'users' table which includes a column 'creditcard', so that I can see each user's credit card number.
I am also comparing the name of the user with the name of the credit card owner so it populates the table according to the user.
I couldn't find any information about the specific problem I am having here.
Here's how I am trying to write:
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'INSERT INTO users (creditcard) SELECT number,name FROM creditcards WHERE users.name = creditcards.name';
const userCreateModel = `
CREATE TABLE IF NOT EXISTS users (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(45) NOT NULL,
username VARCHAR(45) NOT NULL,
email VARCHAR(45) NOT NULL,
phonenumber VARCHAR(45) NOT NULL,
password VARCHAR(255) NOT NULL,
creditcard INT(11),
salt VARCHAR(255),
created_at DATE,
update_at DATE,
deleted_at DATE,
lastSignIn DATE,
PRIMARY key (id)
)
`;
const CreditCardModel = `
CREATE TABLE IF NOT EXISTS creditcards (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR (25) NOT NULL,
type VARCHAR(10) NOT NULL,
number INT(12) NOT NULL,
expiration DATE,
svss INT(3) NOT NULL,
created_at DATE,
PRIMARY key (id)
)
`;
I am trying to create a user named ula and then a credit card with the name ula (and all other columns) which I am sending from postman.
The credit card part in nodejs looks like this:
const createCreditCard = async (req, res, next) => {
const {
name,
type,
number,
expiration,
svss
}: {
name: String,
type: String,
number: String,
expiration: String,
svss: String
} = req.body;
const createAt = new Date(Date.now());
try {
const createNewCreditCard = 'INSERT INTO creditcards (name, type, number, expiration, svss) VALUES (?,?,?,?,?)';
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'UPDATE users SET creditcard=' + number + ' WHERE name="' + name + '"';
console.log(results);
}
});
res.status(201).send({ success: true, message: 'New credit card was created', data: {name, type, number, expiration, svss} });
} catch (error) {
res.status(500).send({ success: false, message: 'Server error' });
}
await next;
}
The server returns 201, I go to mysql, open users, see column creditcard and its NULL.
Because the entry already exists in the database for users table, you should use UPDATE instead of INSERT.
An example that should work with your code (you already know name and number as vars because you just created the credit card info with them, no need to select them again):
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'UPDATE users SET creditcard=' + number + ' WHERE name="' + name + '"';
EDIT: this is the new code from your edit. You already use prepared statements, so forget my notice about that. I've updated the query to follow this. What was missing in your code is that you need to actually do the query! Only declaring the constant won't do anything to your database..
try {
const createNewCreditCard = 'INSERT INTO creditcards (name, type, number, expiration, svss) VALUES (?,?,?,?,?)';
con.query(createNewCreditCard, [name, type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
console.log(results);
const JoinCreditCard = 'UPDATE users SET creditcard=? WHERE name=?';
con.query(JoinCreditCard, [number, name], (err, results) => {
if (err) {
console.error(err);
} else {
console.log(results);
}
});
}
});
res.status(201).send({ success: true, message: 'New credit card was created', data: {name, type, number, expiration, svss} });
} catch (error) {
res.status(500).send({ success: false, message: 'Server error' });
}
NOTE: you should know that using the name to reference the credit card will not allow you to have multiple credit cards for one user, and should be careful about users with the same name, or else this query will update both users. It would be safer to always use the user id field in the WHERE clause. (you should know it at this point)
THIS IS WHAT I RECOMMEND:
it's usually better that the creditcard in users only stores the id from the creditcards table. Like this, relations are on the primary key and it's more optimized (you need to get the id after the credit card creation request, in an inner SELECT in following code).
use the ids to identify rows updates, to prevent 2 users to be updated
delete name from creditcards table, it's already in users
having a third table to reference the relations like states user1974729 is not mandatory, however, it will be the case if you conveniently want to be able to have more than one credit card per user or more than one user that share a card (1 to n relation)
code:
//relation based on id instead of number stored in users + name removed. I assume at this point, you know the id of your user (in var "id" used below in `WHERE` clause)
con.query(createNewCreditCard, [type, number, expiration, svss], (err, results) => {
if (err) {
console.error(err);
} else {
const JoinCreditCard = 'UPDATE users SET creditcard=(SELECT id FROM creditcards WHERE type="' + type + '" AND number="' + number + '" AND expiration="' + expiration + '" AND svss="' + svss + '") WHERE id="' + id + '"';
//no change in userCreateModel
//deleted "name" in CreditCardModel
const CreditCardModel = `
CREATE TABLE IF NOT EXISTS creditcards (
id INT(11) NOT NULL AUTO_INCREMENT,
type VARCHAR(10) NOT NULL,
number INT(12) NOT NULL,
expiration DATE,
svss INT(3) NOT NULL,
created_at DATE,
PRIMARY key (id)
)
`;
it is important that the tables are in normalized forms.
There should be 3 tables.
Users -- all the user data
Credit cards -- all the credit card related information.
Users credit card map -- map users to credit card information.

Mysql, Node, query within a query, how to populate property in map function from another query

Firstly, if anyone can edit my question title or question to make more sense, please do.
I have a node/express app making mysql queries with mysql.js. I have a query that looks up a table of questions and then runs a map function on the results. Within that map function, I need to query another table, of answers, corresponding to each record in the questions table. The value I need is the number of answers to that question, ie the number of records in each answers table. I've tried all kinds of different examples, but nothing quite fits my case in a way that makes sense to me. New at Node and Express, and even MySQL so having a hard time picking out quite what to.
I understand that the problem is the async nature of node. getAnswersCount() returns "count" before the query finishes. Below is my code. Need some advice on how to achieve this.
The value 123 is assigned to count just to clarify the trace results.
app.get('/', (req, res) => {
db.query('SELECT * FROM questions LIMIT 0, 100',
(error, results) => {
if (error) throw error;
questions = results.map(q => ({
id: q.id,
title: q.title,
description: q.description,
answers: getAnswersCount( q.id )
}));
res.send( questions );
});
});
const getAnswersCount = ( id ) =>
{
const tableName = 'answers_' + id;
var count = 123;
var sql = `CREATE TABLE IF NOT EXISTS ${tableName}(
id int primary key not null,
answer varchar(250) not null
)`;
db.query( sql,
(error, results) => {
if (error) throw error;
//console.log( 'answers table created!' );
});
sql = `SELECT COUNT(*) AS answersCount FROM ${tableName}`;
db.query( sql,
(error, results) => {
if (error) throw error;
//console.log( count ); // will=123
count = results[0].answersCount;
//console.log( count ); // will = results[0].answerCount
});
// I know this code runs before the query finishes, so what to do?
//console.log( count ); //still 123 instead of results[0].answersCount
return count;
}
EDIT: After attempting various versions of Michael Platt's suggestion in his answer without success, I finally worked out a solution using Express callbacks and a promise, adding the answers values to the questions array afterwards:
app.get( '/', (req, res, next ) => {
db.query('SELECT * FROM questions LIMIT 0, 100',
(error, results) => {
if (error) throw error;
questions = results.map(q => ({
id: q.id,
title: q.title,
description: q.description,
}));
next();
});
}, (req, res ) => {
questions.map( currentElem => {
getAnswersCount( currentElem.id ).then( rowData => {
currentElem.answers = rowData[0].answersCount;
if( currentElem.id == questions.length ) res.send( questions );
});
});
});
const getAnswersCount = ( id ) => {
const tableName = 'answers_' + id;
var sql = `CREATE TABLE IF NOT EXISTS ${tableName}(
id int primary key not null,
answer varchar(250) not null
)`;
db.query( sql,
(error, results) => {
if (error) throw error;
//console.log( 'answers table created!' );
});
sql = `SELECT COUNT(*) AS answersCount FROM ${tableName}`;
return new Promise( ( resolve, reject ) => {
db.query( sql, ( error, results ) => {
if ( error ) return reject( err );
resolve( results );
});
});
}
I'm not sure which database module you are using to connect to and query the database but you could make the method async and then await the response from the query like so:
const getAnswersCount = async ( id ) =>
{
const tableName = 'answers_' + id;
var count = 123;
var sql = `CREATE TABLE IF NOT EXISTS ${tableName}(
id int primary key not null,
answer varchar(250) not null
)`;
var results = await db.query(sql);
sql = `SELECT COUNT(*) AS answersCount FROM ${tableName}`;
var count = db.query(sql)[0].answerCount;
// I know this code runs before the query finishes, so what to do?
//console.log( count ); //still 123 instead of results[0].answersCount
return count;
}
app.get('/', async (req, res) => {
db.query('SELECT * FROM questions LIMIT 0, 100',
(error, results) => {
if (error) throw error;
questions = results.map(q => {
const answerCount = await getAnswersCount( q.id )
return {
id: q.id,
title: q.title,
description: q.description,
answers: answerCount
}
}));
res.send( questions );
});
});
I think that will give you what you want and run correctly but it might require a bit of tweaking. You may need to async the function on the actual route itself as well and await the call for getAnswersCount but that should just about do it.

Unknown column in field list nodejs

I have the following code in nodejs. I am using npm's mysql library and I know that all the columns are correct in mysql database but I keep getting the following error: "Unknown column 's3_id' in 'field list'" but when I do select s3_id from custom_videos I get rows back. How can I have an unknown column that exists?
router.post("/submitCustomVideo", async (req, res, next) => {
try {
const data = {};
const {
s3Id,
name,
renderTime,
duration,
description,
selectedCategories,
selectedKeywords,
customFields
} = req.body;
const VALUES = {
s3_id: s3Id,
name,
duration,
description,
render_time: renderTime,
custom_fields: customFields
};
const updateCustomVideoInfoResult = await database.query(
"call updateCustomVideoInfo(?)",
[VALUES]
);
} catch (error) {
console.log(error);
next(error);
}
});
heres my stored procedure
CREATE DEFINER=`mystuff`#`%` PROCEDURE `updateCustomVideoInfo`(s3_id_param varchar(255), name_param varchar(255), duration_param int, description_param varchar(255), render_time_param int, custom_fields_param json)
BEGIN
UPDATE custom_videos SET name = name_param, duration = duration_param, description = description_param, render_time = render_time_param, custom_fields = custom_fields_param WHERE s3_id = s3_id_param;
END
Try to set the columns as a string and also check your datatype for columns.

Get ID of last inserted element

Basically I have two table
User -> id, name , email , fname, lname etc...
Device -> id, name, user_id, etc......
here first I will insert data into User table and I get result,
from that result how to get the Id of the User table entry so that I can use is as user_id for the entry in device
basically user_id is foreign key referring User table
My insert code goes like this
exports.user = function(req,res){
var user_email = req.param('email', null);
var user_fname = req.param('fname', null);
var user_lname = req.param('lname', null);
var user_phone = req.param('phone', null);
var user_description = req.param('description',null);
var user_data = {
table:TABLE_USER,
data:{
'email':user_email,
'fname':user_fname,
'lname':user_lname,
'phone':user_phone,
'description':user_description
}
}
db.insert(user_data,function (result) {
//How to get the ID of the last inserted row from result,
// get Id and insert in device table
res.writeHeader(200, {"Content-Type": "text/plain"});
res.write(result[0] + " ");
res.end();
}
);
}
Just have a look at the documentation : Getting the id of an inserted row
Their code example :
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function(err, result) {
if (err) throw err;
console.log(result.insertId);
});