0

I'm trying to add mongoose Id's to my 2 arrays, but it comes back as empty arrays. I can't seem to find what's wrong here is my function,

exports.create = (body) => {
    console.log(body.projectName);
    const theDate = getDate();
    qpTemplate.findOne().sort({version: -1}).exec(function(err, doc) {
        var answerArray = [];
        var questionArray = [];
        var newProject = new projectModel({
        _id: id(),
        owner: Id,
        projectName: body.projectName,
        date: theDate,
        version: 1.0,
        });
        var qp = new questionPackageModel ({
          _id: id(),
          version: 1,
          questionIds: [], // this one i want to populate
          projectId: newProject._id
        });
        console.log("hej")
        doc.questionIds.map(theId => {
          questionTemplate.findById(theId, function (err, question) {
            var theQuestion = new questionModel({
                    _id: id(),
                    qpId: qp._id,
                    categoryId: question.categoryId,
                    order: question.order,
                    version: question.version,
                    question: question.question,
                    answerIds: [], // this one i want to populate
                    name: question.name,
                    legacyName: question.legacyName,
                    description: question.description
            })
                  question.answerIds.map(answerId => {
                    answerTemplate.findById(answerId, function (err, answer) {
                      var theAnswer = new answerModel({
                        _id: id(),
                        questionId: theQuestion._id,
                        name: answer.name,
                        order: answer.order,
                        answerText: answer.answerText,
                        value: answer.value,
                        placeholder: answer.placeholder,
                        settings:answer.settings,
                        description: answer.description
                      })
                      theQuestion.answerIds.push(theAnswer._id); // returns an empty array at the end
                      answerArray.push(theAnswer);
                      theAnswer.save();
                    });
                })

                qp.questionIds.push(theQuestion._id); // returns an empty array in the end
                questionArray.push(theQuestion);
                theQuestion.save()
           });
        })
        newProject.qpId = qp._id;
        qp.save();
        newProject.save();
        console.log(questionArray);
        console.log(newProject)
        return(items={answerArray,questionArray,qp,newProject})
      })

  }

What i'm trying to accomplish is to connect the models to eachother with their ids that's why I'm adding their id's to the array. I don't want the whole object in there since i'm then pushing this data to a redux client that require a flat state.

** I'm thankful for every answer! **

4
  • Hey, maybe this article about built-in update many with Mongoose can help you: medium.com/@salonimalhotra1ind/… Commented Jul 9, 2018 at 12:58
  • Where is your id function ? How you define it ? Commented Jul 9, 2018 at 12:58
  • Hi thanks for answer, but they don't cover arrays there :P Commented Jul 9, 2018 at 12:59
  • Hi i define it like this: var Id = mongoose.Types.ObjectId(); Commented Jul 9, 2018 at 13:00

1 Answer 1

1

The main issue is using a synchronous operation (map) with asynchronous lookups (findById) and then saving the document before the asynchronous operations have completed. You will need to use something like async/await, Promises, or some asynchronous library to ensure all asynchronous operations are completed before you attempt to save the document.

Currently the code flow is:

  • Lookup template (async)
    • Create two documents (sync)
    • Map over template array (sync)
    • Lookup questions (async) Everything nested below won't finish before save
    • Create new document (sync)
    • Map over template array (sync)
      • Lookup answers (async) Everything nested below won't finish before save
      • Attempt to push to array (sync)
      • Attempt to push to array (sync)
    • Save documents (async)

Without a lot of refactoring for optimizations you could start with using Promise.all to wrap all of the mapped lookups and return them:

// Pseudo untested code focusing on the promise aspect only
// `create` is now a Promise
exports create = (body) => {
  return qpTemplate.findOne().exec().then((template) => {
    // Create projectModel and questionPackageModel documents
    newProject.qpId = qp._id;

    return Promise.all(
      template.questionIds.map((theId) =>
        questionTemplate.findById(theId).exec().then((question) => {
          // Create questionModel document
          qp.questionIds.push(theQuestion._id);

          return Promise.all(
            question.answerIds.map((answerId) =>
              answerTemplate.findById(answerId).exec().then((answer) => {
                // Create answerModel document
                theQuestion.answerIds.push(answer._id);
                return theAnswer.save();
            )
          ).then(() => theQuestion.save());
        }
      ).then(
        () => Promise.all([qp.save(), newProject.save()])
      ).then(
        () => {answerArray,questionArray,qp,newProject}
      )
    );
 }
Sign up to request clarification or add additional context in comments.

4 Comments

How would you write it?
I don't get it, i've been looking up aync / await, but I don't seem to get it to work, should I do .then() ?
@Charlie I've included some pseudo code to guide you but if you aren't familiar with promises (for which async/await is a nice sugar syntax for them) then I would begin with researching how promises work.
Thank you :) i tried your code and i get this error , Can't save() the same doc multiple times in parallel. I guess i have to research some more about promises. It's just that I only have this function that needs it in my whole project..

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.