0

We are trying to iterate over all collaborators POSTed as an array to the endpoint and push them into collaboratorsArray. We don't want the function saveProject to execute until the forEach loop has finished.

The result we're getting at the moment is that saveProject is not waiting and therefore collaboratorsArray is an empty array when the project is saved.

Note that we are both new to Node.js and Promise. We would highly appreciate any advice that you have!

Here's our code

export const newProject = async (req, res) => {
  const { userID } = req.params
  const { name, description, collaborators } = req.body

  let collaboratorsArray = []

  const loopCollaborators = async () => {
    if (collaborators) { 
      return new Promise((resolve, reject) => {
        collaborators.forEach(async username => {      
          const collaborator = await User.findOne({
            username
          })
          collaboratorsArray.push(collaborator)
          console.log('CollaboratorsArray ', collaboratorsArray)
        })
          resolve(collaboratorsArray)
      })
    }
  }

  const saveProject = async () => {
    const getCollaboratorsProject = await loopCollaborators()

    if (getCollaboratorsProject) {
      try {
        console.log('Project save now', collaboratorsArray)
        const project = await new Project({
          name,
          description,
          collaborators: collaboratorsArray,
          projectOwner: userID
        }).save()
    
        res.status(201).json({ 
          success: true,
          projectID: project._id,
          name: project.name, 
          description: project.description,
          collaborators: project.collaborators,
          projectOwner: project.projectOwner
        })
      } catch (error) {
        res.status(400).json({ success: false, message: 'Invalid request', error })
      }
    }
  }
  saveProject()
}

Here's our model

export const Project = mongoose.model('Project', {
  name: {
    type: String,
    required: true,
    maxlength: 20
  },
  description: {
    type: String
  },
  collaborators: {
    type: Array
  }, 
  projectOwner: {
    type: String,
    required: true
  }
})
Isabella
  • 23
  • 2

1 Answers1

1

Don't use Array.forEach loop with asycn/await, use traditional for loop. Why ? see more Using async/await with a forEach loop;

async function newProject(req, res) {
    try {
        let { userID } = req.params,
            { name, description, collaborators } = req.body,
            collaboratorsArray = [];

        if (!collaborators) return

        for (const username of collaborators) {
            const collaborator = await User.findOne({ username });
            collaboratorsArray.push(collaborator);
        }

        console.log('CollaboratorsArray ', collaboratorsArray);

        const project = await new Project({
            name, description,
            collaborators: collaboratorsArray,
            projectOwner: userID
        }).save();

        res.status(201).json({
            success: true,
            projectID: project._id,
            name: project.name,
            description: project.description,
            collaborators: project.collaborators,
            projectOwner: project.projectOwner
        });

    } catch (error) {
        res.status(400).json({ success: false, message: 'Invalid request', error })
    }
}

I think Express.js handles error for you, so you don't need to use try/catch block in every request handler!, use a global error handler in express...

Nur
  • 2,361
  • 2
  • 16
  • 34