create data to three tables at once with Sequelizer - mysql

I want to get data from form and based on that, add data to three tables in mySQL, I use Sequelize to do so, However I don't how to do so, my current idea gives error:
Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers
after they are sent to the client
My code is like this:
app.post("/device/add", (req, res) => {
db.Devices.create({
device_id: req.body.device_id,
server: req.body.server,
type: req.body.type
})
.then(result => {
res.json(result);
})
.catch(err => {
throw err;
});
db.Modules.create({
device_id: req.body.device_id,
device_options: req.body.device_options,,
sleep_options: req.body.sleep_options
})
.then(result => {
res.json(result);
})
.catch(err => {
throw err;
});
db.Tests.create({
device_id: req.body.device_id,
gsm_tests: req.body.gsm_tests,
led_tests: req.body.led_tests,
})
.then(result => {
res.json(result);
})
.catch(err => {
throw err;
});
});
can I somehow create it in one response? Or how to make it work

The problem is that you are trying to send again a response after you have sent one.
For more clarification, refer here
You can use Promise.all() to accumulate the results and then send it in one res.json() call.
const createDevice = db.Devices.create({
device_id: req.body.device_id,
server: req.body.server,
type: req.body.type
})
const createModules = db.Modules.create({
device_id: req.body.device_id,
device_options: req.body.device_options,
sleep_options: req.body.sleep_options
})
const createTests = db.Tests.create({
device_id: req.body.device_id,
gsm_tests: req.body.gsm_tests,
led_tests: req.body.led_tests,
})
Promise
.all([createDevice , createModules , createTests ])
.then(result=> {
res.json({
devices: result[0],
modules: result[1],
test : result[2]
});
})
.catch(err => {
throw(err);
});

Related

TypeError: Product.findById is not a function

exports.postDeleteProduct = (req, res, next) => {
const prodId = req.body.productId;
Product.findById(prodId)
.then((product) => {
return product.destroy();
})
.then((result) => {
res.redirect("/admin/products");
})
.catch((err) => console.log(err));
};
TypeError: Product.findById is not a function
I am getting "TypeError: Product.findById is not a function."
I am using the mysql database and retreiving the data using sequelize. But it is showing error when I gone to alter the values(editing and deliting) in the databse.
I tried findByAll() .But it is giving the 500 status in the network console.
In sequelize ORM findById is not there instead of that u can try below code
exports.postDeleteProduct = (req, res, next) => {
const prodId = req.body.productId;
Product.findByPK(prodId)
.then((product) => {
return product.destroy();
})
.then((result) => {
res.redirect("/admin/products");
})
.catch((err) => console.log(err));
};
Or Else u can use findOne instead of findByPk
Happy Coding :)

Delete an image of a post stored in a backend folder when i delete a user of a social network application

I have a problem on my application, it is a social network. The user can create a post with a message and an image, stored in a backend images folder thanks to Multer. I use sequelize and MySql. When I delete a post, the image is indeed deleted in the images folder since I use multer in my post deletion function so everything goes well but when I delete the author, since I go through a relationship between tables so that when I delete a user, their posts are deleted. This works but in this case the images are not deleted from the folder they are stored in, since Multer is not in the loop. How do I get the images to be deleted from the images folder too in this specific case? Thank you for your help !
`
// Template for the Post table
const User = require("../models/User");
const Sequelize = require("sequelize");
const database = require("../config/database");
const Post = database.define("post", {
content: { type: Sequelize.STRING, allowNull: false },
image: { type: Sequelize.STRING, allowNull: true },
likes: { type: Sequelize.INTEGER, allowNull: false, default: 0 },
});
module.exports = Post;
// Relationship with the User table
User.hasMany(Post, { onDelete: "CASCADE", foreignKey: "userId" });
Post.belongsTo(User, { onDelete: "CASCADE" });
`
`
// deletePost function
exports.deleteOnePost = (req, res, next) => {
Post.findOne({ where: { id: req.params.id } })
.then((post) => {
if (!post) {
return res.status(404).json({
error: new Error("Post non trouvé !"),
});
}
if (post.userId === req.auth.userId || req.auth.userAdmin) {
if (post.image) {
const filename = post.image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
Post.destroy({ where: { id: req.params.id } })
.then(() => res.status(200).json({ message: "Post sans supprimé" }))
.catch((error) => res.status(400).json({ error }));
} else {
return res.status(403).json({
error: new Error("Requête non autorisée !"),
});
}
})
.catch((error) => res.status(500).json({ error }));
};
`
#Anatoly Thank you very much for your help, I'm sorry, I'm a beginner, I tried to adapt what you sent me to the method I use. I don't use the async/await method much and don't know much about it. Do you think I'm getting closer to the solution with what i made ? thanks again !
`
exports.deleteUser = (req, res, next) => {
const userId = req.params.id;
User.findOne({ where: { id: userId } }).then((user) => {
if (!user) {
return res.status(404).json({
error: new Error("User not found!"),
});
}
});
const userPosts = User.getAllPosts();
const postImages = posts.map((x) => x.image).filter((x) => x);
User.destroy({ where: { id: userId } })
.then((post) => {
Post.findOne({ where: { userId } })
.then((post) => {
Post.destroy({ where: { userId } }).then((res) =>
res.status(200).json({
message: "User is deleted",
})
);
for (const image of postImages) {
const filename = image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
})
.catch((error) =>
res.status(400).json({
error,
})
);
})
.catch((error) => res.status(500).json({ error }));
};
`
I don't see how Multer is related to a file deletion. It only helps you to store them. Any way you just need to get all posts of a certain user and delete them and a user in a transaction and then delete their images in a cycle:
// I did not use try/catch for simplicity
exports.deleteUser = async (req, res, next) => {
// get the user id somehow (req.params or the request context, for instance)
const userId = ...
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({
error: new Error("User not found!"),
});
}
const userPosts = await user.getPosts();
const postImages = poists.map(x => x.image).filter(x => x);
// here 'sequelize' is the Sequelize instance, you used to register models
await sequelize,transaction(async transaction => {
await Post.destroy({ where: { userId } })
await User.destroy({ where: { id: userId } })
});
for (const image of postImages) {
const filename = image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
res.status(200).json({ message: "User is deleted" }))
}
I come back to put the fonction that works with my method, i often use ".then()" ".catch()", many thanks to Anatoly for helping me to find the solution, here is the result of my work :
exports.deleteUser = (req, res, next) => {
User.findOne({ where: { id: req.params.id } })
.then((user) => {
if (!user) {
return res.status(404).json({
error: new Error("user not found !"),
});
}
// I get all the posts of the author
Post.findAll({ where: { userId: req.params.id } })
.then((posts) => {
// I start a loop in the posts of the author to find the posts with an image
posts.forEach((post) => {
if (post.image) {
// I erase the files in the images backend directory
const filename = post.image.split("/images/")[1];
fs.unlink(`images/${filename}`, () => {});
}
// Now i can erase the author
User.destroy({ where: { id: req.params.id } })
.then(() =>
res.status(200).json({
message: "User erased !",
})
)
.catch((error) =>
res.status(400).json({
error,
})
);
});
})
.catch((error) =>
res.status(400).json({
error,
})
);
})
.catch((error) => res.status(500).json({ error }));
};

Check if a user is present in the database for a parameter other than ID

I created 3 functions: findOne, create and update. Respectively the methods are GET, POST, PUT.
I changed my API path, it used to be /api/users/:id, now it's /api/users/:sub.
routes.js:
module.exports = app => {
const users = require("../controllers/user.controller.js");
const router = require("express").Router();
// Create a new User
router.post("/", users.create);
// Retrieve a single User with sub
router.get("/:sub", users.findOne);
// Update a User with sub
router.put("/:sub", users.update);
// Delete a User with sub
router.delete("/:sub", users.delete);
app.use('/api/users', router);
};
controller.js:
// Save User in the database
User.create(user)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while creating the Users."
});
});
};
// Find a single User with an id and sub
exports.findOne = (req, res) => {
const sub = req.params.sub;
User.findOne({sub})
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message: "Error retrieving User with id=" +sub
});
});
};
// Update a User by the sub in the request
exports.update = (req, res) => {
const sub = req.params.sub;
User.update(req.body, {
where: { sub }
})
.then(num => {
if (sub) {
res.send({
message: "User was updated successfully."
});
} else {
res.send({
message: `Cannot update User with sub=. Maybe User was not found or req.body is empty!`
});
}
})
.catch(err => {
res.status(500).send({
message: "Error updating User with sub="
});
});
};
What I wanted to do was: check if the user_id provided by the authentication provider was present in my database.
If yes, update user data with that user_id.
If not, create a new user record
This is the front-end part involved:
//INFO SAVE AND UPDATE CONDITION
const userExist = InfoDataService.get(data.sub)
.then((response) => {
console.log('find', response.data);
return true;
});
if ( userExist ) {
InfoDataService.create(data)
.then((response) => {
console.log('create', response.data);
setInfo({
id: response.data.id,
sub: response.data.sub,
email: response.data.email,
firstname: response.data.firstname,
lastname: response.data.lastname,
});
})
} else {
InfoDataService.update(sub, data)
.then((response) => {
console.log(response.data);
})
.catch((e) => {
console.error(e);
});
}
};
I thought userInDatabase could only give true or false, so I used it as an argument in the if statement. It does not work and just updates.
If you need any other information, please ask, I have just started and I hope I have given the necessary info.
EDIT
Through findOne I can find the entire object in my database, but I thought that putting the function as an if condition could give me true if it found the object with its sub; false if he found nothing.
This is not the case, in fact in the code I just updated, although findOne works correctly, it continues to execute always and only create.

How can i use the querystring for knex?

router.get("/stocks/symbols", function (req, res, next) {
req.db
.from("stocks")
.select("name","symbol","industry")
.modify(function(queryBuilder) {
if (req.query.param) {
queryBuilder.where('industry',req.query.param);
}
})
.where('timestamp', '=', '2020-03-24T00:00:00Z')
.then((rows) => {
res.json(rows)
})
.catch((err) => {
console.log(err)
res.json({ Error: false, Message: "Error in MySQL query" })
})
})
I'm trying to make such a functionality to use querystring.
At the moment this runs without error but doesn't do anything.
Whether I put ?industry=h or anything after the route, it returns the same data.
There was an example I followed, but for some reason its not working.
What else am i missing?
router.get("/stocks/symbols/:industry", function (req, res, next) {
req.db
.from("stocks")
.select("name","symbol","industry")
.where('timestamp', '=', '2020-03-24T00:00:00Z')
.where("industry", "like", `%${req.params.industry}%`)
.then((rows) => {
res.json({ Error: false, Message: "Success", Cities: rows })
})
.catch((err) => {
console.log(err)
res.json({ Error: true, Message: "Error in MySQL query" })
})
})
This does similar job that i want to do but it doesn't use the querystring.
You need to apply the correct query parameter - in your code you use query.param meaning that your url would need to contain /stocks/symbols?param=tbd
If you're expecting industry as a query-param, you need to change it to:
.modify(function(queryBuilder) {
if (req.query.industry) {
queryBuilder.where('industry',req.query.industry);
}
})

Asynch problem when fetching MySQL and EXPRESS

I'm trying to simple add a new property in an object. The array of objs is being fetched from my database and then I try to add a property which is also fetched from my database. Although when I try to manipulate it I'm receiving "undefined".
Is it indeed an asynch problem?
Am I doing any silly mistakes?
Those are questions that surrounds my head at the moment.
Code:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRows = rows.map(el => {
Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows, fieldData]) => {
console.log(rows);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows.name
};
}).catch(err => console.log(err));
// return{
// ...el,
// userOfReport: 'Joao'
// };
});
res.render('user/index', { reports: rows, pageTitle: 'Social Reporter', path: '/' });
}).catch(err => console.log(err));
};
Obs This works if comment this out and comment Report.fetchUserNameOfReport function->
// return{
// ...el,
// userOfReport: 'Joao'
// };
Expected result:
{
idComplaint: 83059,
title: '4444',
description: '4444',
image: '4444',
location: '4444',
UserInfo_idPessoa: 80068,
userOfReport: 'Joao'
}
Actual result:
undefined
Thank you in advance!
You never return anything in your .map, so all of the values of modifiedRows will be undefined. You can map them all to promises to get all the values, and then access the modified rows once you wait for all of the promises to resolve. Also, you're shadowing your variable by declaring rows and fieldData multiple times:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRowPromises = rows.map(el => {
return Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows2, fieldData2]) => {
console.log(rows2);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
});
Promise.all(modifiedRowPromises).then(modifiedRows => {
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' });
}).catch(console.log);
}).catch(err => console.log(err));
};
Alternatively, if you use async/await syntax, this can be achieved much more cleanly:
exports.getIndex = async (req, res, next) => {
try {
const [rows, fieldData] = Report.fetchAll();
const modifiedRowPromises = rows.map(async el => {
const [rows2, fieldData2] = await Report.fetchUserNameOfReport(el.UserInfo_idPessoa);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
const modifiedRows = await Promise.all(modifiedRowPromises);
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' };
} catch (err) {
console.log(err);
}
};