0

I'm trying to upload multiple images using cloudinary in node.js application. Storing every image URL in an array. But my array is empty outside the loop. Can't understand why.

const postCreate = (req,res,next) => {
    req.body.post.images = [];
    const file_length = req.files.length;
    let arr = [];
    //console.log(req.files);
    new Promise((resolve, reject) => {
        req.files.forEach((file,index) => {
            i = index;
            cloudinary.v2.uploader.upload(file.path)
                .then(image => {
                    //console.log(image);
                    req.body.post.images.push({
                        url: image.secure_url,
                        public_id: image.public_id
                    });
                    console.log("array", req.body.post.images);//there array is containing the element which is pushed.
                });
            console.log("arr", req.body.post.images);//but there it is showing empty array .Can't understand why array is empty.
        });
        resolve();
    }).then(() => {
            Post.create(req.body.post)
                .then(post => {
                 //console.log(req.body.post.images);
                    res.redirect(`/posts/${post.id}`);
                }).catch(err => {
                    console.log('Error will saving posts from db ', err);
                    return next(err);
                });
    });
  • It's because `cloudinary.v2.uploader.upload` is async function. You are printing your array just after this async function call. You should wait for the promise using `then` or modern `async await` construction. – lankovova Mar 24 '19 at 13:13
  • possible duplicate of https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – AZ_ Mar 24 '19 at 13:15
  • and also cloudinary.v2.uploader.upload is already a promise you dont need to wrap it around another promise. – AZ_ Mar 24 '19 at 13:16

3 Answers3

0

The 2nd log message actually gets called first while the array is empty because the code in the then block is waiting for something asynchronous to complete.

VorpalSword
  • 1,223
  • 2
  • 10
  • 25
0

Each of the uploads is asynchronous and returns a promise.

You need to have all those promises resolve before moving on to the final then()

You can map an array of those promises and use Promise.all() to return the full array to the final then()

Something like:

const doUpload = (file) => {
  // return the upload promise
  return cloudinary.v2.uploader.upload(file.path).then(image => {
      return {
        url: image.secure_url,
        public_id: image.public_id
      };
    });
}

const postCreate = (req, res, next) => {
  // map array of individual upload promises
  const uploadPromises = req.files.map(doUpload);

  Promise.all(uploadPromises).then(imagesArray => {
    // assign new array to post body
    req.body.post.images = imagesArray;

    Post.create(req.body.post)
      .then(post => {
        //console.log(req.body.post.images);
        res.redirect(`/posts/${post.id}`);
      }).catch(err => {
        console.log('Error will saving posts from db ', err);
        return next(err);
      });
  }).catch(err=> console.log('One of the uploads failed'));

}
charlietfl
  • 170,828
  • 13
  • 121
  • 150
0

your problem is your print function fire before loop is complated so you have to use async-await for proper solution and learn more about this topic

please refer https://blog.risingstack.com/mastering-async-await-in-nodejs for your solution

it describe the async await for your proper output