Insert into two dependent tables in MySQL with node.js - mysql

I am new to MySQL and node.js (as well as the callback). I try to insert data into table B, which depends on data in table A. Here is an example.
employee table (table A):
CREATE TABLE employees (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(50),
location varchar(50),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
age table (table B, I do not include age column in table A on purpose):
CREATE TABLE age (
id int(11) NOT NULL AUTO_INCREMENT,
index_id int(11),
age int(50),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
The problem:
For each row inserted into table A, I can get the id for it. I want to use the id as the index_id in table B, and insert the corresponding age info into age table B. The problem occurs when I have multiple rows to insert.
The example:
I implement the following function to achieve above goal.
var mysql = require("mysql");
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "root",
database: "sitepoint"
});
function insert_employees() {
var employees = [
{name: 'Jasmine', location: 'Australia', age: 24},
{name: 'Jay', location: 'India', age: 25},
{name: 'Jim', location: 'Germany', age: 26},
{name: 'Lesley', location: 'Scotland', age: 27}
];
var name_id;
for (var i = 0; i < 4; i++) {
var employee = employees[i];
var command = sprintf('INSERT INTO employees (name, location) VALUES ("%s", "%s");', employee.name, employee.location);
con.query(command, function (err, res) {
if (err) throw err;
name_id = res.insertId;
console.log('Last insert ID in employees:', res.insertID);
// insert age here
var age = employee.age;
var command = sprintf('INSERT INTO age (index_id, age) VALUES (%d, %d);', name_id, age);
con.query(command, function (err, res) {
if (err) throw err;
});
});
}
}
The Output:
The employee table is fine, but for the age table, the age column is 27 for all fields, instead of 24, 25, 26, 27
The Question:
I think the problem is on my misuse of callback feature, but I still don't know how to solve it. Could anyone help me with it? Thanks a lot!

var employee = employees[i];
Change the above line to below, so that variable employee has the correct scope:
let employee = employees[i];
Add the following to the beginning of your script, so that let works:
'use strict';

Related

How can I INSERT if row doesn't exist, else UPDATE that row?

At the front-end, whenever I press submit an answer to a question, it'll create 1 result_ID that has these columns.
result_ID is auto-increment, question_ID is relation with the same question_ID from questions table.
If it's the first time the user chooses the answer, it'll create an answer_result (i parse in answer_ID) and answer_checkResult (value 1 or 0 to identify it's correct or incorrect), and a history_ID to identify each record separately.
History_ID is a different table that has the quiz_ID (to identify topic) and user_ID
example: History_ID 221 has 4 questions in there, and has 4 answers with 4 answer_result.
What I don't know is how can I create a situation if the row doesn't exist, it'll run INSERT INTO situation, and else if it already exists (because the user can change the answer multiple times in 1 question), it'll UPDATE. I've just created only the INSERT INTO option, but I don't know how to do the update in this model at the same time with INSERT INTO.
This is my history_result.model that I've created, I don't know how to create an if-else to update and create at the same time...
history_result.model
const HistoryResult = function (history_result) {
this.question_ID = history_result.question_ID;
this.answer_result = history_result.answer_result;
this.answer_checkResult = history_result.answer_checkResult;
this.history_ID = history_result.history_ID;
};
HistoryResult.create = async (newHistoryResult, result) => {
await db.query(
`INSERT INTO history_result SET question_ID = ?, answer_result = ?, answer_checkResult = ?, history_ID = ?`,
[
newHistoryResult.question_ID,
newHistoryResult.answer_result,
newHistoryResult.answer_checkResult,
newHistoryResult.history_ID,
],
(err, data) => {
if (err) {
result(err, null);
return;
} else {
return result(null, data);
}
}
);
};
And here's how I create the history_result controller
const HistoryResult = require("../models/history_result.model");
exports.createHistoryResult = async (req, res) => {
let { history_ID } = req.params;
let { question_ID, answer_result, answer_checkResult } = req.body;
let historyResult = new HistoryResult({
question_ID: question_ID,
answer_result: answer_result,
answer_checkResult: answer_checkResult,
history_ID: history_ID,
});
HistoryResult.create(historyResult, (err, data) => {
if (err) {
res.status(500).send({
message: err.message || "Error while creating result",
});
}
res.send(data);
});
};
Is there anyways I can achieve this? Thanks.
Yes, you can.
but first you have to make question_ID as PRIMARY KEY. And second parameter that you pass to db.query is object that contains history_result's attributes
INSERT INTO history_result
SET ?
ON DUPLICATE KEY UPDATE
answer_result = VALUES(answer_result),
answer_checkResult = VALUES(answer_checkResult),
history_ID = VALUES(history_ID)
db.query(query, objectHere, (err, data) => {
if (err) {
result(err, null);
return;
} else {
return result(null, data);
}
}))
First, please read the MySQL Insert or Update on duplicate-key update tutorial,
or this Official MySQL INSERT ... ON DUPLICATE KEY UPDATE Statement document
Now back to your question. As I understand, the question_ID and history_ID pair in the history_result table would be unique, as each user will only give one answer to a question in a quiz.
First you would need to create a unique index constraints of the pair (question_ID, history_ID) of your table.
ALTER TABLE history_result
ADD CONSTRAINT uc_question_history
UNIQUE (question_ID,history_ID);
And then issue an INSERT ON DUPLICATE KEY UPDATE statement to achive the effect.
INSERT INTO history_result
(
question_ID, answer_result, history_ID
)
VALUES
(14, 21, 12)
ON DUPLICATE KEY UPDATE
answer_result = 21;
If the question_ID = 14 and history_ID = 12 row already existed (scenario that user has already answer this question), it will trigger to update the answer_result. If not, it will insert a new record.
The DUPLICATE KEY constraint is met if a new row is a duplicate in UNIQUE index or PRIMARY KEY. In our case, it's the unique index of (question_ID, history_ID), hence the UPDATE statement will be invoked.

AWS Aurora DB Combine Data from Multiple SQL Statements

I have three tables with data schema, like:
TABLE user (
user_id BINARY(16) PRIMARY KEY NOT NULL,
created DATETIME NOT NULL,
last_updated DATETIME,
coordinator BINARY(16),
num_updates INT NOT NULL
);
TABLE summary (
user_id BINARY(16) PRIMARY KEY NOT NULL,
calculation_time DATETIME NOT NULL,
calculation_method VARCHAR(25) NOT NULL,
label VARCHAR(50) NOT NULL,
critical_count INT NOT NULL,
median_risk FLOAT(10)
);
TABLE actions(
user_id BINARY(16) PRIMARY KEY NOT NULL,
label VARCHAR(50) NOT NULL,
access_count INT NOT NULL,
median FLOAT(10)
);
The data for all the users (user table) is simply fetched using the lambda handler function in the following manner:
const AWS = require('aws-sdk');
const rdsDataService = new AWS.RDSDataService();
module.exports.hello = async (event, context, callback) => {
const req_id = "5a9dbfca-74d6-471a-af27-31beb4b53bb2";
const sql = 'SELECT * FROM user WHERE user_id=:id';
try {
const params = {
resourceArn: 'arn:aws:rds:us-west-********************',
secretArn: 'arn:aws:secretsmanager:us-west**************',
sql,
database: 'dev_db1',
continueAfterTimeout: true,
includeResultMetadata: true,
parameters: [{ 'name': 'id', 'value': { 'stringValue': `${req_id}` } }]
}
const db_res = await rdsDataService.executeStatement(params).promise();
const convertToJson = (dbresponse) => {
const columns = dbresponse.columnMetadata.map(col => col.name);
const row_data = dbresponse.records.map(row => {
const json_obj = {};
row.map((val, i) => {
json_obj[columns[i]] = Object.values(val)[0];
});
return json_obj;
});
return row_data;
};
const modified_data = convertToJson(db_res);
const response = {
body: {
statusCode: 200,
message: 'Data fetched successfully',
data: modified_data,
}
};
callback(null, response);
} catch (error) {
console.log('Error Received', error);
const error_res = {
body: {
statusCode: error.statusCode,
message: error.message,
data: null
}
}
callback(null, error_res);
}
};
If the same is followed for another table summary or actions, it also works. Now, I need to combine all the columns of these three tables and then return the data (returned rows should match on the basis of req_id).
My working snippet: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=016ecc94c792611fbaca810605e81a6a
But the final result obtained contains the column user_id in duplicated form i.e. three times inclusion. I don't need the same column to be repeated thrice.
I am a bit new to handling MySQL queries, so unable to figure out the exact reason for the error even when the table exists. The MYSQL version used in Aurora is 5.7.
Any help to resolve the same is appreciated!
Plan A: Explicitly specify the columns you want. Extra benefit: You can get rid of the ids, which tend to be useless to others reading the output.
Plan B: (This option is not always possible.) Instead of JOIN .. ON t1.a = t2.a, say JOIN .. USING(a)
I like to use short aliases. Here's doing all things together:
SELECT u.last_name, u.first_name,
s.risk_score,
t.likes
FROM user AS u
JOIN summary AS s USING(user_id)
LEFT JOIN test AS t USING(user_id)
In general, it is not wise to have a 1:1 relationship (as you have via user_id); you may as well have all the columns in a single table.
try this
SELECT users.*, summary.* from users, summary WHERE users.user_id = summary.user_id
OR
SELECT * from users, summary WHERE users.user_id = summary.user_id

Stored Procedure Output in NodeJS

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.

MYSQL: BAD_FIELD_ERROR Unknown column in 'field list'

First time using MySQL (this is in a node/react app) and am encountering an error trying to insert some values into a table. The specific error message I am getting is:
Error: ER_BAD_FIELD_ERROR: Unknown column 'name' in 'field list'
Here is my table:
const table =
"CREATE TABLE IF NOT EXISTS
posts(id int AUTO_INCREMENT,
name VARCHAR(30),
email VARCHAR(50),
content VARCHAR(500),
stamp VARCHAR(40),
PRIMARY KEY(id))";
and here is the query:
// Insert post 1
app.get("/addpost1", (req, res) => {
let post = {
name: "Joe Blogs",
email: "jblogs#gmail.com",
content:
"Interesting post Phil. It's great to see that a blog really can come alive when the comments update in real-time. The commenting system becomes a conversation platform.",
stamp: "July 30 2019"
};
let sql = "INSERT INTO posts SET ?";
let query = db.query(sql, post, (err, result) => {
if (err) throw err;
console.log(result);
res.send("Post 1 added...");
});
});
I am continually running into errors with this. Any help appreciated.
This is the right syntax:
INSERT INTO `table`(`column1`, `column2`) VALUES ([value-1],[value-2])
so in your code would be like:
INSERT INTO `posts` (`name`, `email`, `content`) VALUES ([name:], [email:], [content:])

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);
});