For循环中的NodeJS和Mongoose回调

时间:2017-10-26 14:18:55

标签: javascript node.js mongodb mongoose callback

所以这就是问题所在。我有一个处理预订创建的REST API,但是,在将预订保存在mongo中之前,它会验证是否存在与其他预订的冲突。

exports.create = function(req, res) {
    var new_type = new Model(req.body);
    var newBooking = new_type._doc;

    //check if the new booking clashes with existing bookings
    validateBooking.bookingClash(newBooking, function(clash){
        if(clash == null) // no clashes, therefore save new booking
        {
            new_type.save(function(err, type) {
                if (err)
                {
                    res.send(err); //error saving
                }
                else{
                    res.json(type); //return saved new booking
                }
            });
        }
        else //clash with booking
        {
            //respond with "clashDate"
        }
    });
};

这里有验证功能,可以检查同一天是否与预订发生冲突:

exports.bookingClash = function (booking, clash) {
    //find the bookings for the same court on the same day
    var courtId = (booking.courtId).toString();

    Model.find({courtId: courtId, date: booking.date}, function(err, bookings) {
        if(err == null && bookings == null)
        {
            //no bookings found so no clashes
            clash(null);
        }
        else //bookings found
        { 
            //for each booking found, check if the booking start hour falls between other booking hours
            for(var i = 0; i<bookings.length ; i++)
            {
                //here is where I check if the new booking clashes with bookings that are already in the DB 
                {
                    //the new booking clashes
                    //return booking date of the clash
                    clash(clashDate); //return the clashDate in order to tell the front-end
                    return;
                }
            }
            //if no clashes with bookings, return null
            clash(null);
        }
    });
};

所以,所有这一切都适用于一个新的预订。但是,现在我希望能够处理递归预订(每周预订)。我重新创建了“创建”功能,并在validateBooking.bookingClash内调用for loop函数。

不幸的是,当我运行它时,它会完美地调用bookingClash函数,但是当它到达在数据库中进行搜索的行时:

Model.find({courtId: courtId, date: booking.date}, function(err, bookings)

它不等待回调,在处理响应“clash”之前,使i ++继续。

如何让它工作并等待回调?

var array = req.body;
var clashes = [];

for(var i = 0; i<array.length;i++)
     {
         validateBooking.bookingClash(array[i], function(clash)
         {
           if(clash)
           {
               clashes.push(clash);
           }
           else{
              console.log("no clash");
           }
         }
     }

5 个答案:

答案 0 :(得分:1)

看起来像一个基本的异步调用问题,for循环不等待回调被调用。

您可以使用async&#39;系列&#39; exmaple而不是for循环的函数。这样每个发现都会在前一个发现之后被调用。

Mongoose还有基于承诺的语法,可以帮助您:http://mongoosejs.com/docs/promises.html

答案 1 :(得分:1)

您可以使用async eachSeries

SUMX

答案 2 :(得分:1)

由于您使用的是回调函数,因此有两种方法可以尝试解决此问题: 1)使用一些外部库,允许您执行异步映射操作并对每个冲突运行所有检查。完成后,检查合并后的结果,然后进行相应的处理 我建议使用async library

您的代码看起来像: async.map(array,(entry,callback) => validateBooking.bookingClash(entry,callback),(error,mappingResults)=>{...})

2)你可以尝试将此函数更改为递归函数

`function recursiveValidation(arrayToCheck,mainCallback){ 
if(arrayToCheck.length === 0) {
   return cb(null} // end of array without errors
} 

validateBooking.bookingClash(_.head(arrayToCheck), function(clash)
     {
       if(clash)
       {
           return mainCallback(clash);
       }

        return  recursiveValidation(_.tail(arrayToCheck),mainCallback);

     }
}`

上面的代码只是一个模型,但它应该表明这一点。 _是lodash

答案 3 :(得分:1)

无需更改代码中的任何内容,除非声明使用let而不是var,并且循环应该有效。

var array = req.body; var clashes = [];

`
for(**let** i = 0; i<array.length;i++)
     {
         validateBooking.bookingClash(array[i], function(clash)
         {
           if(clash)
           {
               clashes.push(clash);
           }
           else{
              console.log("no clash");
           }
         }
     }`

您必须了解let和var之间的区别。另外,为什么var不能用于在循环内运行异步代码。 了解let:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

答案 4 :(得分:0)

我在找到所有答案后找到了完成这项工作的方法。

我必须做的是:

validateBooking.singleBooking(new_type._doc, newBookingClubId, function (clash) {
                if (clash == null) // no clash
                {
                    validatorArray.push(0);
                    if(validatorArray.length == array.length) //has received everything from mongo
                    {
                        console.log("Clashes: " + clashes.toString());
                        if(validatorArray.indexOf(1) > -1) //contains a clash
                        {
                            var error = {
                                code: 409,
                                message: "409 Conflict",
                                clashes: clashes
                            };
                            errorsHandler.handleError(error, res);
                        }

这样,我创建了一个名为“validatorArray”的数组,每当我从Mongo收到一些东西时就会调用它。

这样我就可以轻松地比较预订数组的长度和validatorArray长度。当它们相等时,它意味着它从mongo收到了所有东西,并且可以发回回复。

感谢您的帮助!