1

I know this topic as already asked many times before but I didn't find the right answer to do what I want.

Actually, I try to save two different list of JSON object in MongoDB via Mongoose. To perform both at the same time I use 'async'. However, when I save it with the command insertMany() I get an error because he calls the callback of async before finishing the insertMany(). Therefore answer[0] is not defined.

What will be the proper way of doing it ?

Here is my code with the async:

const mongoose = require("mongoose");
const async = require("async");
const utils = require("../utils");

const experimentCreate = function(req, res) {
  let resData = {};
  let experimentList = req.body.experiment;
  let datasetList = req.body.datasetList;

  async.parallel(
        {
          dataset: function(callback) {
            setTimeout(function() {
              answer = utils.createDataset(datasetList);
              callback(answer[0], answer[1]);
            }, 100);
          },
          experiment: function(callback) {
            setTimeout(function() {
              answer = utils.createExp(experimentList);
              callback(answer[0], answer[1]);
            }, 100);
          }
        },
        function(err, result) {
          if (err) {
            console.log("Error dataset or metadata creation: " + err);
            sendJSONresponse(res, 404, err);
          } else {
            console.log("Experiment created.");
            resData.push(result.dataset);
            resData.push(result.experiment);
            console.log(resData);
            sendJSONresponse(res, 200, resData);
          }
        }
      );
};

Then the two functions called createExp and createDataset are the same in another file. Like this:

const createDataset = function(list) {
  let datasetList = [];
  for (item of list) {
    let temp = {
      _id: mongoose.Types.ObjectId(),
      name: item.name,
      description: item.description,
      type: item.type,
    };
    datasetList.push(temp);
  }

  Dataset.insertMany(datasetList, (err, ds) => {
    if (err) {
      console.log("Error dataset creation: " + err);
      return [err, null];
    } else {
      console.log("All dataset created.");
      return [null, ds];
    }
  });
};

1 Answer 1

1

There's a few problems with your code. For one, you're not returning anything in your createDataset function. You're returning a value in the callback of insertMany but it doesn't return that value to the caller of createDataset as it's within another scope. To solve this issue, you can wrap your Dataset.insertMany in a promise, and resolve or reject depending on the result of Data.insertMany like this:

const createDataset = function(list) {
  let datasetList = [];
  for (item of list) {
    let temp = {
      _id: mongoose.Types.ObjectId(),
      name: item.name,
      description: item.description,
      type: item.type,
    };
    datasetList.push(temp);
  }

  return new Promise((resolve, reject) => {
    Dataset.insertMany(datasetList, (err, ds) => {
      if (err) {
        console.log("Error dataset creation: " + err);
        reject(err);
      } else {
        console.log("All dataset created.");
        resolve(ds);
      }
    });
  });   
};

Now your return object is no longer going to be an array so you won't be able to access both the error and the result via answer[0] and answer[1]. You're going to need to chain a then call after you call createDataset and use callback(null, answer) in the then call (as that means createDataset executed successfully) or use callback(err) if createDataset throws an error like below:

dataset: function(callback) {
  setTimeout(function() {
    utils.createDataset(datasetList).then(answer => {
      callback(null, answer);
    }).catch(err => callback(err)); // handle error here);
  }, 100);
}

Note: You'll most likely need to alter your createExp code to be structurally similar to what I've produced above if it's also utilizing asynchronous functions.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.