I'm using fs-extra library to delete some image files on post request in my node js app. every time I call /deleteproduct route everything works fine. my product is removed from database and fs-extra callback doesn't throw any error even though files are not removed! I don't know what is the reason. I think maybe I'm doing something wrong with async/await functions.
this is my code:
router.post('/deleteproduct', async (req, res) => {
try {
const id = req.body.id;
const deleteProduct = await prisma.product.findUnique({
where: { id: id }
});
const images = JSON.parse(deleteProduct.image);
for(let i = 0; i < images.length; i++) {
await fsExtra.remove(path.join(__dirname, `public/images/${images[i]}`), (err) => {
if (err) console.log(err);
});
console.log(images[i]);
}
await prisma.product.delete({
where: { id: id }
});
res.status(200).json({ msg: "Deleted product with id: " + id });
} catch (error) {
res.json({ msg: error });
}
});
EDIT: image files are inside images folder in public directory.
directory image
please comment if you need more info
directories image:
directories image
cpanel.js is deleting the files
There might be two problems here. First, your are not using correct path to reference your files correctly. Secondly, you are using await and callbacks at the same time. You can do something like this.
try {
const images = JSON.parse(deleteProduct.image);
const imageProm = [];
for(let i = 0; i < images.length; i++) {
imageProm.push(fsExtra.remove(path.join(__dirname, `public/images/${images[i]}`)
}
const result = await Promise.all(imageProm);
await prisma.product.delete({
where: { id: id }
});
}
catch (e) {console.log(e)}
If the above solution doesn't work why can't you use fs.unlink a native method provided to work for such scenarios. Try using that.
Note: whenever you use async/await use try/catch block to catch errors.
Instead of this:
await fsExtra.remove(path.join(__dirname, `public/images/${images[i]}`), (err) => {
if (err) console.log(err);
});
Could you directly try this:
await fsExtra.remove(path.join(__dirname, `public/images/${images[i]}`));
fs-extra returns a promise so this should work. Adding a try/catch to check for errors can also be implemented
Related
I have been playing around with ExpressJS I normally use FastAPI. I can't seem to generate an error using Supabase.
I have this endpoint
app.delete('/api/delete-book/:id', cors(corsOptions), async (req, res) => {
const {data, error} = await supabase
.from('books-express')
.delete()
.match({id: req.params.id})
if (error) {
res.status(400).send({message: `ERROR! ${error.message}`})
}
if (data)
res.send({
message: `Book ID ${req.params.id} has been deleted from the database`,
})
})
This works when it comes to deleting a book via an ID. However if I enter an invalid ID I get the data if block firing.
There is no book with an ID of 222 in the database, I would expect the error to fire but its just null
Any ideas here?
This is expected behaviour; not matching any rows is not considered an error condition in postgres.
If you'd like to check if any rows were deleted, you can use something akin to (on supabase-js 2.x):
const { data, error } = await supabase.from('books-express')
.delete()
.match({id: req.params.id})
.select() // not needed on 1.x libs
if (error || data.length === 0) {
res.status(400).send({...})
}
Hellow all,
I'm Newbie to Nodejs and Firebase, I need two functionalities to takes place in a single function and also I have written a piece of code it's works fine.
But My question is, the code I have written is the correct way to achieve the multiple functionality or do we have any other alternate method(correct way) to achieve the same functionality.
Doubt :
Retrieving relevant details of project ----> Inside Callback function ----> saving data to another table ----> Inside Callback function ----> Deleting data from table -----> Inside Callback function ----> response
Do we need to write the functionality inside the nested callback function to achieve the output or is there is any other way to achieve it .
// Nodejs Post Function
app.post('/delete_user_request_project/', function (req, res)
{
if (!is_admin_login(req.cookies.login_type))
{
return res.redirect('/');
}
var project_id = req.body.project_id; // Getting the project Id
let del_ref = admin.database().ref("user_request_project/" + project_id); // Targeting the details of the project to fetch that particular data
del_ref.once("value", function (snapshot)
{
var request_project_obj = snapshot.val(); // fetching the details of project
if (request_project_obj != null)
{
let update_ref = admin.database().ref("deleted_user_request_project/" + project_id);
update_ref.set(
request_project_obj // Updating project details to another table
).then(function ()
{
del_ref.remove().then(function () // Deleting the details from project Table
{
return res.status(200).send('success');
});
});
}
else
{
var error = "プロジェクトが存在しない";
req.flash("error", error_message);
return res.send({
status: 'error',
error: error
});
}
});
})
TIA
I would suggest you use the Promise version of the once() method instead of the Callback version, as follows. It will allow you to correctly chain the different promises returned by the asynchronous Firebase method.
app.post('/delete_user_request_project/', function (req, res) {
if (!is_admin_login(req.cookies.login_type)) {
return res.redirect('/');
}
var project_id = req.body.project_id; // Getting the project Id
let del_ref = admin.database().ref("user_request_project/" + project_id); // Targeting the details of the project to fetch that particular data
del_ref.once("value")
.then(function (snapshot) {
var request_project_obj = snapshot.val(); // fetching the details of project
if (request_project_obj != null) {
let update_ref = admin.database().ref("deleted_user_request_project/" + project_id);
return update_ref.set(request_project_obj); // Updating project details to another table
}
else {
throw new Error('request_project_obj null');
}
})
.then(function () {
return del_ref.remove();
})
.then(function () // Deleting the details from project Table
{
return res.status(200).send('success');
})
.catch(function (error) {
if (error.message === 'request_project_obj null') {
var error = "プロジェクトが存在しない";
req.flash("error", error_message);
return res.send({
status: 'error',
error: error
});
} else {
//...
}
})
})
I need to query my database for users based on an array of emails and then execute a function for each result, I do this with eachAsync:
mongoose.model('User')
.find({email: {$in: ['foo#bar.com', 'bar#foo.com']}})
/* -- Run side effects before continuing -- */
.cursor()
.eachAsync((doc) => {
// do stuff
});
The problem I'm having is that I need to return a 404 status if any of the users with the given emails do not exist.
I've been looking through the mongoose docs but I can't seem to find a way of running "side effects" when working with queries. Simply "resolving" the DocumentQuery with .then doesn't work since you can't turn it into a cursor afterwards.
How can I achieve this?
You could try implementing it as shown below. I hope it helps.
// Function using async/await
getCursor: async (_, res) => {
try {
const result = []; // To hold result of cursor
const searchArray = ['foo#bar.com', 'bar#foo.com'];
let hasError = false; // to track error when email from find isn't in the array
const cursor = await mongoose.model('User').find({ email: { $in: searchArray } }).cursor();
// NOTE: Use cursor.on('data') to read the stream of data passed
cursor.on('data', (cursorChunk) => {
// NOTE: Run your side effect before continuing
if (searchArray.indexOf(cursorChunk.email) === -1) {
hasError = true;
res.status(404).json({ message: 'Resource not found!' });
} else {
// Note: Push chunk to result array if you need it
result.push(cursorChunk);
}
});
// NOTE: listen to the cursor.on('end')
cursor.on('end', () => {
// Do stuff or return result to client
if (!hasError) {
res.status(200).json({ result, success: true });
}
});
} catch (error) {
// Do error log and/or return to client
res.status(404).json({ error, message: 'Resource not found!' });
}
}
I am trying to write a simple function to grab the id of a specific instance based on matching criteria from mongodb using the official node package 'mongodb'.
My function works as I can console log the data but I am unable to return the data to use it as I intended to do as you can see.
const mongo = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
// Function for finding database id of device based on deviceKey, The database is written into
// the code under the const 'db' as is the collection.
async function fetchId(deviceKey) {
const client = await mongo.connect(url, { useNewUrlParser: true });
const db = client.db('telcos');
const collection = db.collection('device');
try {
await collection.find({"deviceKey": deviceKey}).toArray((err, response) => {
if (err) throw err;
console.log(response[0]._id); // << works logs _id
return response[0]._id; // << does nothing... ?
})
} finally {
client.close();
}
}
// # fetchId() USAGE EXAMPLE
//
// fetchId(112233); < include deviceKey to extract id
//
// returns database id of device with deviceKey 112233
// Run test on fetchId() to see if it works
fetchId("112233")
.then(function(id) {
console.dir(id); // << undefined
})
.catch(function(error) {
console.log(error);
});
Why does my test return undefined but my console.log() inside the function works?
It looks like you're combining callback code with async/await code in an odd way. Your function fetchId isn't returning anything at all, which is why you don't see id after fetching.
try {
const response = await collection.find(...).toArray()
return response[0]._id
}...
If we weren't able to await collection.find(...).toArray() and needed to manually convert this from using callbacks to promises, we'd have to do something like:
function fetchId (id) {
// this function returns a promise
return new Promise((resolve, reject) => {
...
collection.find(...).toArray((err, response) => {
// within the callback, returning values doesn't do anything
if (err) return reject(err);
return resolve(response[0]._id);
})
});
}
You are returning a value but handled like a promise is being returned.Please try this code.I had not tested it.
const mongo = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
// Function for finding database id of device based on deviceKey, The database is written into
// the code under the const 'db' as is the collection.
async function fetchId(deviceKey) {
return new Promise((resolve,reject)=>{
const client = await mongo.connect(url, { useNewUrlParser: true });
const db = client.db('telcos');
const collection = db.collection('device');
try {
await collection.find({"deviceKey": deviceKey}).toArray((err, response) => {
if (err) throw err;
console.log(response[0]._id); // << works logs _id
return resolve(response[0]._id); // << does nothing... ?
})
}
catch(error){
return reject(error);
}
finally {
client.close();
}
});
}
// # fetchId() USAGE EXAMPLE
//
// fetchId(112233); < include deviceKey to extract id
//
// returns database id of device with deviceKey 112233
// Run test on fetchId() to see if it works
fetchId("112233")
.then(function(id) {
console.dir(id); // << undefined
})
.catch(function(error) {
console.log(error);
});
i am pushing errors in array by using promises but before it push errors in array it check the condition for insert data like in else i am inserting data.
var errorsArr= [];
var username = new Promise(function(resolve,reject){
User.findOne({ "username": req.body.username },function(err,user){
if(err)
reject(err);
if(user) {
resolve(1);
}else{
resolve(0);
}
});
});
username.then(function(data){
if( data == 1 )
errorsArr.push({"msg": "Username already been taken."});
}).catch(function(err){
console.log(err);
});
var email = new Promise(function(resolve,reject){
User.findOne({ "email": req.body.email },function(err,user){
if(err)
reject(err);
if(user) {
resolve(1);
}else{
resolve(0);
}
});
});
email.then(function(data){
if( data == 1 )
errorsArr.push({"msg": "email already been taken."});
}).catch(function(err){
console.log(err);
});
if(errorsArr.length >0)
{
req.session.error = errorsArr;
return res.redirect('/auth/Registration');
}
else {
var newUser = new User();
newUser.username = req.body.username;
newUser.password = req.body.password;
newUser.sex = req.body.sex;
newUser.email = req.body.email;
newUser.phoneNumber = req.body.phoneNumber;
newUser.age = req.body.age;
newUser.designation = req.body.designation;
newUser.timing = req.body.timing;
var CurrentDate = moment.tz(new Date(req.body.joiningDate), "Asia/Karachi").unix();
newUser.joiningDate = CurrentDate;
newUser.save(function (err, user) {
if (!err)
return res.redirect('/auth/Login');
});
}
can you please help me to do it in better way i am new in node.js. Thanks in advance.
Promise.all is your solution. It waits for all the promises.
Promise.all([p1,p2,..]).then(function() {
// all loaded
}, function() {
// one or more failed
});
Reference Link:
http://www.html5rocks.com/en/tutorials/es6/promises/
You're mixing asynchronous and synchronous code.
Synchronous:
var errorsArr= [];
Asynchronous:
var username = new Promise(...{
...
});
username.then(..
errorsArr.push(...);
})
Synchronous:
if (errorsArr.length > 0) {
...
The asynchronous part in the middle (where you do errorsArr.push(…)) doesn't actually happen before your synchronous code at the end (if (errorsArr.length > 0)).
You need to convert all your synchronous code to asynchronous as well, if you want it to execute in succession to the other async code.
Other answers have already explained that how, which is by using Promise.all
I would also like to suggest using Bluebird Promise library which offers promisification so you can just promisify your mongoose models, instead of manually creating promises for every operation.
Promise.promisifyAll(User);
var username = User.findOneAsync(...); // the new "findOneAsync" method returns a promise
username.then(data => ...)
You might also wanna checkout the upcoming ES2016 additions to javascript that further simplify promises with async/await. With it you can get rid of .then(..) entirely and just write:
app.get('/', async function(req, res) { // < async function
try {
var username = await User.findOneAsync(...); // await statements
var email = await User.findOneAsync(...);
// do stuff
} catch(err){
// handle errors
}
});
Checkout this great article on async/await. Although this requires you add an extra transpilation step by using Babel or Typescript. There's also the recently released Microsoft's fork of Node that ships with chakra engine (instead of V8) which already supports async/await as well.
Here is an example
Promise.all([
Reservation.find({'parking.owner': req.payload.id}).exec(),
Reservation.count({'parking.owner': req.payload.id}).exec(),
Reservation.aggregate([
{ $match: {
_id: req.payload.id
}},
{ $group: {
_id: "$_id",
total: { $sum: "$price" }
}}
])
]).then(results=>{
const list = results[0]
const count = results[1]
const sum = results[2]
res.status(200).json({list,count,sum});
})
after all Promises have been done ... use Promise.all
the checking for errors at the bottom of your code could be written:
Promise.all([username, email])
.then(function(results) {
if(errorsArr.length >0)
{
...
}
else {
...
}
});
Quickest and easiest change to your code - refactoring your code can make it even sleeker
#Jaromanda X answer is correct if there is username and email checks are independent and no order has to be followed. Else, you have to do a promise chain.