0

I want to upload the files to Cloudinary and then get the 'secure_url' s and insert them into a MySQL database. However my current code immediately execute the SQL function. How to make the SQL function wait till the Cloudinary upload finishes.

Below is the code :

app.post('/create', upload.array('uploaded_file'), function (req, res) {
    console.log(req)

    var wallet = req.body.wallet
    var name = req.body.fname
    var nic = req.body.nic
    var nicfront = req.files[0].path;
    var nicback = req.files[1].path;
    var selfie = req.files[2].path;
    var state = 1

    var frontURL = "temp_string"
    var backURL = "temp_string"
    var selfieURL = "temp_string"

    cloudinary.uploader.upload(nicfront, function (err, result) {
        console.log("Result: ", result);
        frontURL = result.secure_url;
    });
    
    cloudinary.uploader.upload(nicback, function (err, result) {
        console.log("Result: ", result);
        backURL = result.secure_url;
    });

    cloudinary.uploader.upload(selfie, function (err, result) {
        console.log("Result: ", result);
        selfieURL = result.secure_url;
    });

    // Insert into MySQL Database
    db.query("INSERT INTO applications (wallet, name, nic, nicfront, nicback, selfie, state) VALUE (?,?,?,?,?,?,?)", [wallet, name, nic, frontURL, backURL, selfieURL, state], (err, result) => {
        if (err) {
            console.log(err)
        } else {
            res.send("Inserted into MySQL!")
        }
    })
});

app.listen(3001, () => {
    db.connect(function (err) {
        if (err) throw err;
    });
});
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – derpirscher Mar 23 '23 at 15:38

2 Answers2

1

Node.js I/O is async, so each of your lines starts uploading and moves onto the next line. Use something like async.parallel to manage the flow of your code so it waits for the three uploads to complete before running the insert:

const async = require('async')
app.post('/create', upload.array('uploaded_file'), function (req, res) {
    console.log(req)

    var wallet = req.body.wallet
    var name = req.body.fname
    var nic = req.body.nic
    var nicfront = req.files[0].path;
    var nicback = req.files[1].path;
    var selfie = req.files[2].path;
    var state = 1

    // Run the three uploads in parallel
    async.parallel({
        frontURL: (done) => {
            cloudinary.uploader.upload(nicfront, function (err, result) {
                console.log("Result: ", result);
                done(null,result.secure_url);
            });
        },
        backURL: (done) => {
            cloudinary.uploader.upload(nicback, function (err, result) {
                console.log("Result: ", result);
                done(null,result.secure_url);
            });
        },
        selfieURL: (done) => {
            cloudinary.uploader.upload(selfie, function (err, result) {
                console.log("Result: ", result);
                done(null,result.secure_url);
            });
        }
    }, (err, urls) => {
        // Insert into MySQL Database
        db.query("INSERT INTO applications (wallet, name, nic, nicfront, nicback, selfie, state) VALUE (?,?,?,?,?,?,?)", [wallet, name, nic, urls.frontURL, urls.backURL, urls.selfieURL, state], (err, result) => {
            if (err) {
                console.log(err)
            } else {
                res.send("Inserted into MySQL!")
            }
        })
    })
});

app.listen(3001, () => {
    db.connect(function (err) {
        if (err) throw err;
    });
});

Edit: you could also switch to using promises with async/await if cloudinary.uploader.upload returns a promise object when not passed a callback. This might make the code more readable, but I used the async module since your existing code is callback-based. Also, make sure to handle those errors! :)

Evan Shortiss
  • 1,638
  • 1
  • 10
  • 15
  • Thank you for the response. I Tried your suggestion, got this error. Not sure how to fix that : ) Error: ER_BAD_NULL_ERROR: Column 'nicfront' cannot be null – Sandaru Fernando Mar 23 '23 at 16:18
  • There was a typo in my answer. Note that `frontURL` was passed to the parallel object twice. Fixed now. – Evan Shortiss Mar 23 '23 at 16:25
0

I'm not sure if this is the best way to fix this, but somehow it worked. I'm sharing it here just in case someone finds it useful in the future.

app.post('/create', upload.array('uploaded_file'), function (req, res) {
    console.log(req)

    var wallet = req.body.wallet
    var name = req.body.fname
    var nic = req.body.nic
    var nicfront = req.files[0].path;
    var nicback = req.files[1].path;
    var selfie = req.files[2].path;
    var state = 1

    cloudinary.uploader.upload(nicfront, function (err, result) {
        console.log("Result: ", result);
        frontURL = result.secure_url;

        cloudinary.uploader.upload(nicback, function (err, result) {
            console.log("Result: ", result);
            backURL = result.secure_url;

            cloudinary.uploader.upload(selfie, function (err, result) {
                console.log("Result: ", result);
                selfieURL = result.secure_url;
            }).then(() => {
                // Insert into MySQL Database
                db.query("INSERT INTO applications (wallet, name, nic, nicfront, nicback, selfie, state) VALUE (?,?,?,?,?,?,?)", [wallet, name, nic, frontURL, backURL, selfieURL, state], (err, result) => {
                    if (err) {
                        console.log(err)
                    } else {
                        res.send("Inserted into MySQL!")
                    }
                })
            });
        });
    });
});

app.listen(3001, () => {
    db.connect(function (err) {
        if (err) throw err;
        console.log("Connected to MySQL!");
    });
});
  • This works, but is known as "callback hell". It also mixes promises with callbacks where you add the then. It will also run the uploads one at a time, so is a little slower than using the async solution I posted. Nice work finding a solution on your own! – Evan Shortiss Mar 23 '23 at 16:48