Building a simple ToDo app in React/NodeJS/Express with MySQL. Users join a group ("family" in the code), then tasks are viewable filtered by familyId. To create a task, I first have a query that finds the user's familyId from the Users table, then I want to include that familyId value in the subsequent INSERT query for creating the task row in the Tasks table. My task.model.js is below:
const sql = require("./db.js");
// constructor
const Task = function(task) {
this.title = task.title;
this.familyId = task.familyId;
this.description = task.description;
this.completed = task.completed;
this.startDate = task.startDate;
this.userId = task.userId;
};
Task.create = (task, result) => {
sql.query("SELECT familyId FROM users WHERE userId = ?", task.userId, (err, res) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(err, null);
}
sql.query("INSERT INTO tasks (familyId, title, description, completed, startDate) VALUES (?,?,?,?,?)", [result, task.title, task.description, task.completed, task.startDate], (err, res) => {
if (err) {
console.log("Error inserting in TASKS: ", err);
return result(err, null);
}
})
console.log("created task: ", { id: res.insertId, ...task });
return result(null, { id: res.insertId, ...task });
});
};
However, I cannot figure out how to properly use the familyId result of the SELECT query as a parameter in the suqsequent INSERT query. I know the overall syntax works because I can manually plug in an ID value as a parameter and the entire operation completes successfully - I just need to know how to use the resule of the first query in the next.
The way you are using it should work but the problem is you have defined the callback as res but are passing result in the 2nd sql query
sql.query("SELECT familyId FROM users WHERE userId = ?", task.userId, (err, res) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(err, null);
}
//res should have the value for the familyId of the given user so in next line pass res not result
sql.query("INSERT INTO tasks (familyId, title, description, completed, startDate) VALUES (?,?,?,?,?)", [res[0].familyId, task.title, task.description, task.completed, task.startDate], (err, res) => {
if (err) {
console.log("Error inserting in TASKS: ", err);
return result(err, null);
}
})
console.log("created task: ", { id: res.insertId, ...task });
return result(null, { id: res.insertId, ...task });
});
SQL returns array in result , so use result[0] to get first Object ,
and then access the object key by result[0].keyName
Task.create = (task, result) => {
sql.query("SELECT familyId FROM users WHERE userId = ?", task.userId, (err, users) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(err, null);
}
let familyId = users && users[0] ? users[0].familyId : null;
sql.query("INSERT INTO tasks (familyId, title, description, completed, startDate) VALUES (?,?,?,?,?)", [familyId, task.title, task.description, task.completed, task.startDate], (err, res) => {
if (err) {
console.log("Error inserting in TASKS: ", err);
return result(err, null);
}
})
console.log("created task: ", { id: res.insertId, ...task });
return result(null, { id: res.insertId, ...task });
});
};
Related
I am trying to make an API with node, express and mysql.
I have managed to add a record to the database and it works fine with the code below
Student.addStudent = (new_student, result) => {
db.query("INSERT INTO student SET ?", new_student, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
result(null, { id: res.insertId, ...new_student });
});
};
What I would like to do is to say that if this student is a master student, that a second insert query (into a master_student table) is executed but I cannot get this to work.
I thought I would do something like this
Student.addStudent = (new_student, result) => {
db.query("INSERT INTO student SET ?", new_student, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
result(null, {
id: res.insertId,
...new_student
});
});
if (new_student.type == "master") {
db.query(`INSERT INTO master_student (student_id, course) VALUES ("${new_student.student_id}", "${new_student.course}"`, new_student, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
result(null, {
id: res.insertId,
...new_student
});
});
}
};
No matter what I tried, I either get an error that headers have already been sent or that it does not insert it into either table.
How can I execute the second query if a condition is met.
I am aware that the database schema might not be sensible adding the student_id and course into both tables. This is just a simplified example to show the problem
Thanks in advance
Although there are other issues as others said in comments. I believe your main problem here is that the two queries run concurrently and you don't have control on the which of the two runs and completes first.
In any case, result will be called twice and it does not look like what you expect to do with that snippet.
One option to fix the issue is to run the queries sequentially, by moving the second db.query into the first callback. In there also ensure to call result only once.
Student.addStudent = (new_student, result) => {
db.query("INSERT INTO student SET ?", new_student, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (new_student.type == "master") {
db.query(`INSERT INTO master_student (student_id, course) VALUES (?)`, [new_student.student_id, new_student.course], (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
result(null, {
id: res.insertId,
...new_student
});
});
} else {
result(null, {
id: res.insertId,
...new_student
});
}
});
};
User.createuser = (req, result) => {
sql.query("INSERT INTO Users SET ?", req, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
// if (await User.findOne({ where: { username: req.body.username } })) {
// throw 'Username "' + req.body.username + '" is already taken';
// }
console.log("created User: ", { id: res.insertId, ...req });
result(null, { id: res.insertId, ...req });
});
};
Example json object for api create route (post method)
{
"username": "seve",
"user_name": "sev123",
"user_surname": "avcı",
"email": "sevre#gmail.com",
"user_type": "user",
"password": "123456"
}
The "INSERT INTO Users SET ?" query that I use in my code, I want it as a stored procedure, I want it to handle the stored procedure id itself, what is the equivalent of this code's stored procedure?
INSERT INTO users (username, user_name, user_surname, email, user_type, password)
SELECT x->>'$.username', x->>'$.user_name', x->>'$.user_surname', x->>'$.email', x->>'$.user_type', x->>'$.password'
FROM ( SELECT ? AS x ) jsondata
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f190bb4b9d4c3e4003bae631af901d72
I'm using NodeJS to insert a row into MySQL with a "title", "userid" and "opid" field ;
After insertion, I'd like to use the newly created id and the userid to create a new string called "audioname".
Then I'd like update a field called "audioname" with this new "audioname" string
Here's the code I'm using to create the audioname;
const audiopost = new Audiopost({
title: req.body.title,
userid: req.body.userid,
opid: req.body.opid
});
Audiopost.create(audiopost, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while creating the Audiopost."
});
else
var newaudioid = data.id.toString();
var newuserid = data.userid.toString();
var hyphen = "-";
var m4a = ".m4a"
var newaudioname = newuserid + hyphen + newaudioid + m4a;
res.send(newaudioname);
});
};
And here's the model;
const Audiopost = function(audiopost) {
this.userid = audiopost.userid;
this.title = audiopost.title;
this.opid = audiopost.opid;
};
Audiopost.create = (newAudiopost, result) => {
sql.query("INSERT INTO audioposts SET ?", newAudiopost, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
console.log("created audiopost: ", { id: res.insertId, ...newAudiopost });
result(null, { id: res.insertId, ...newAudiopost });
});
};
This will help you I believe,
sql.query("INSERT INTO audioposts SET ?", newAudiopost, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
const insertId = res.insertId;
const userId = newAudiopost.userid;
const m4a = ".m4a";
const audioname = ${insertId}-${userId}${m4a}; //You can change this string in any format
sql.query("UPDATE audioposts SET audioname = ? WHERE id = ?", [audioname, insertId], (err, res, fields) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
})
});
Here's the NodeJS code I'm using to create a customer in my MySql database;
const customer = new Customer({
email: req.body.email,
name: req.body.name,
active: req.body.active
});
Customer.create(customer, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while creating the Customer."
});
else res.send(data);
});
};
Heres' the model;
const Customer = function(customer) {
this.email = customer.email;
this.name = customer.name;
this.active = customer.active;
};
Customer.create = (newCustomer, result) => {
sql.query("INSERT INTO customers SET ?", newCustomer, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
console.log("created customer: ", { id: res.insertId, ...newCustomer });
result(null, { id: res.insertId, ...newCustomer });
});
};
And here's what I'm getting in return;
{"id":8,"email":"harry#gmail.com","name":"harry","active":1}
How can I get it to return just the id as a plain integer instead of the entire JSON string?
To get the specific property from the object. e.g. id, access it as data.id and id is an number which will be treated as status code in express so toString() is needed to convert it to string
The response should be:
res.send(data.id.toString())
I am trying to perform a get with multiple parameters in node.js . I have the following files
entry.routes.js
module.exports = app => {
const entry = require("../controlers/entry.controller.js");
// Retrieve a single Entry with Id
app.get("/entry/:Id", entry.findOne);
app.get("/energy/api/ActualTotalLoad/:AreaName/:Resolution/:Year/:Month/:Day", entry.find1a);
};
ActualTotalLoad.model.js
const sql = require("./db.js");
// constructor
const Entry = function(entry) {
this.Id=entry.Id
};
Entry.findByPk = (Id, result) => {
sql.query(`SELECT * FROM ActualTotalLoad WHERE Id = ${Id}`, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (res.length) {
console.log("found entry: ", res[0]);
result(null, res[0]);
return;
}
// not found Customer with the id
result({ kind: "not_found" }, null);
});
};
Entry.findBy1a = (AreaName,Resolution,Year,Month,Day,result) => {
sql.query(`SELECT AreaName,AreaTypeCodeId,MapCodeId,ResolutionCodeId,Year,Month,Day FROM ActualTotalLoad WHERE AreaName = ${AreaName} AND ResolutionCodeId = ${Resolution} AND Year = ${Year} AND Month = ${Month} AND Day = ${Day}` , (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (res.length) {
console.log("found entry: ", res[0]);
result(null, res[0]);
return;
}
// not found Customer with the id
result({ kind: "not_found" }, null);
});
};
module.exports=Entry;
and the file: entry.controller.js
const Entry = require("../models/ActualTotalLoad.model.js");
// Find a single Customer with a customerId
exports.findOne = (req, res) => {
Entry.findByPk(req.params.Id, (err, data) => {
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `Not found Entry with id ${req.params.Id}.`
});
} else {
res.status(500).send({
message: "Error retrieving Entry with id " + req.params.Id
});
}
} else res.send(data);
});
};
exports.find1a = (req, res) => {
Entry.findBy1a(req.params.AreaName,req.params.Resolution,req.params.Year,req.params.Month,req.params.Day, (err, data) => {
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `Not found Entry with AreaName ${req.params.AreaName}.`
});
} else {
res.status(500).send({
message: "Error retrieving Entry with AreaName " + req.params.AreaName
});
}
} else res.send(data);
});
};
I am trying to perform this get http://localhost:8765/energy/api/ActualTotalLoad/DE-AT-LU/7/2018/1/4
But I get the error "message": "Error retrieving Entry with AreaName DE-AT-LU"
What am I doing wrong?
You should change your WHERE statement like this
SELECT ... WHERE AreaName = "${AreaName}" AND ResolutionCodeId = ${Resolution} AND Year = ${Year} AND Month = ${Month} AND Day = ${Day}
Note: notice the quotes ( "${AreaName}" )
AreaName in your DB schema is problably typed as string (or text), so you need to quote you search criteria as string (surrounding it by " or ')
I assume that ResolutionCodeId, Year Month, and Day are number types, so it's ok to not quote them.