Ad

Async/await Problem, When The My URLs Are Inserting On Database I Am Getting Empty Object

I have created a function inside my route that will upload all the images into Cloudinary 3rd party library and it will return all the URLs links, and I am pushing all the links in my URLs variable and then the links will be stored into the database.

I want until the links are available on my URLs variable it will not insert into my database. I am confused about how I can do it using async/await or using promises

This is my route with function. I am using node, express, multer.

  app.post('/addProduct', async (req, res, next) => {

            let urls = [];

            async function sendImagesToCloudinary() {
                for (let file of req.files) {
                    await cloudinary.uploader.upload(
                        file.path,
                        {
                            public_id: `${Date.now()}`,
                            resource_type: 'auto'
                        }
                    ).then(result => {
                        //del files after upload on cloudinary
                        fs.unlink(file.path, function (err) {
                            if (err) {
                                console.log(err);
                            }
                        });

                        urls.push(result.url);
                    })
                        .catch(err => {
                            console.log(err);
                        });
                }
                res.json(urls);
            }
            sendImagesToCloudinary();
            
           // Publish on database

            const result = await unityMartMediaCollection.insertOne({ urls: urls })
            res.json(result)

        });
Ad

Answer

It's worthwhile to (a) tease apart the various async ops into smaller - clearer, testable - functions, and (b) utilize only one style of promise syntax...

// isolated version of he OP upload
async function upload(file) {
    const params = { public_id: `${Date.now()}`, resource_type: 'auto' }
    return cloudinary.uploader.upload(file.path, params);
}

// this promisify's fs.unlink (probably natively available in fs.promise)
async unlink(file) {
    return new Promise((resolve, reject) => {
        fs.unlink(file.path, error => error? reject(error) : resolve());
    });
}

// upload, then unlink if upload succeeds, return the url upload result
// catch errors here, so other concurrent uploads can continue
async uploadAndUnlink(file) {
    try {
        const url = await upload(file);
        await unlink(file);
        return url
    } catch (err) {
        console.log(err);
    }
}

// implement the route, process the files concurrently
app.post('/addProduct', async (req, res, next) => {
    const promises = req.files.map(file => uploadAndUnlink(file));
    const urls = await Promise.all(promises);
    const result = await unityMartMediaCollection.insertOne({ urls: urls })
    res.json(result);
});

I took the liberty of removing the .json invocation on res inside the URL-producing method. The strong implication from the rest of the code is that the aim is to return (to the client) the result of the unityMartMediaCollection call.

Ad
source: stackoverflow.com
Ad