I've been trying to accomplish to following for the past couple of days, and I just can't solve it. I feel like I've tried everything. So here goes...
My route is given a JSON object which contains all information to create a new Quiz. In other words - an object which contains information about the new quiz, an array of questions, where each question contains an array of answers.
I use the async.js waterfall function, and want to do the following:
Save new quiz to DB, and pass the new quiz ID returned from the DB to the next waterfall function
Loop through each question. Cache the new question ID's returned from DB, and pass them to the next waterfall function. The problem here is caching the ID's. Since the function is async, I can't cache the result anywhere to be used in the next function...
Loop through each answer, and save them to DB
This is what I've got:
router.post('/quiz/create', function (req, res) {
// JSON object with the new Quiz
var json = req.body;
async.waterfall([
function(callback) {
// Returns a Quiz ID for the new quiz, and passes it to the next waterfall function
db.createQuiz(json, function(err, result) {
// ID returned from DB is formatted as [{'': id}], hence result[0]['']
callback(null, result[0]['']);
});
},
function(quizID, callback) {
// Loop through each question in the quiz
async.forEachSeries(json.questions, function(question, callback) {
// Save the question to DB, and get the new question ID returned
db.createQuestion(question, quizID, function(err, result) {
// TODO: cache the new question ID's in an array somewhere to be passed to the next waterfall function
// Start next iteration of the loop
callback();
});
}, function(err) {
// Done with all questions. Pass question ID's to next function
callback(null, cachedQuestionIDs);
});
},
function(cachedQuestionIDs, callback) {
// TODO: access the question ID's, and use them to loop through and save answers to DB
}
], function(err, result) {
res.json({
success: true,
message: 'Quiz created!'
});
});
});
Just store the values in an array outside the async.forEachSeries()
but within the wrapping second function in the async.waterfall()
control flow. You can then return this array when your async.forEachSeries()
is done executing.
function(quizID, callback) {
var cachedQuestionIDs = [];
// Loop through each question in the quiz
async.forEachSeries(json.questions, function(question, callback) {
// Save the question to DB, and get the new question ID returned
db.createQuestion(question, quizID, function(err, result) {
// Store our result
cachedQuestionIDs.push(result);
// Start next iteration of the loop
return callback();
});
}, function(err) {
// Done with all questions. Pass question ID's to next function
return callback(null, cachedQuestionIDs);
});
}
I finally got it to work correctly, with a more elegant solution using nested forEachSeries-loops for the questions and answers. No error handling here. Just to show the basic idea. This is the second function in the waterfall.
function(quizID, callback) {
async.forEachSeries(json.questions, function(question, callback) {
db.registerQuestion(question, quizID, function(err, result) {
async.forEachSeries(question.answers, function(answer, callback) {
db.registerAnswer(answer, result[0][''], callback);
}, function() {
callback();
});
});
}, function() {
callback();
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With