2017-10-26 24 views
0

ここに問題があります。私は予約作成を処理するREST APIを持っていますが、他の予約との衝突があるかどうかをmongo内の予約を保存する前に確認します。Forループ内のNodeJSコールバックとMongooseコールバック

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); 
 
     } 
 
    }); 
 
};

だからこれは1つの新しい予約で動作します。しかし、今では再帰的な予約(毎週の予約)を処理できるようにしたいと考えています。私は "作成"機能を作り直して、for loopの中でvalidateBooking.bookingClash関数を呼び出します。私はこれを実行すると

残念ながら、それは完全にbookingClash関数を呼び出しますが、それはデータベースの検索を行うラインに到達したとき:

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

それは、コールバックのため、応答を処理する前に待機しません。 "クラッシュ"、私は++を作り続ける。

私はそれを動作させ、コールバックを待つことができますか?

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"); 
 
      } 
 
     } 
 
    }

答えて

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」と呼ばれる配列を作成しました。

このようにして、予約の配列の長さとvalidatorArrayの長さを簡単に比較できます。彼らが平等だったとき、それはモンゴからすべてのものを受け取り、その返答を返すことができることを意味した。

ありがとうございました!

1

ループが呼び出されるコールバックを待たないため、基本的な非同期呼び出しの問題のように思えます。

forループの代わりにasync 'series'関数をexmapleに使用できます。このようにして、各検索は前の検索の後に呼び出されます。

マングースもあなたを助けることができる約束ベースの構文は次のとおりです。http://mongoosejs.com/docs/promises.html

1

あなたがこの問題を解決しようとすることができ、2つの方法がありますコールバック関数を使用しているので、あなたがasync eachSeries

async.eachSeries(users, function iterator(user, callback) { 

    if(something) { 
     //thing you want to do 
     callback(); 
    } else { 

     callback(); 
    } 
} 
1

を使用することができます。 は1)外部ライブラリを使用して、非同期マップ操作を実行し、各クラッシュのすべてのチェックを実行できるようにします。彼らは衝突を合わせた結果を確認し、それに応じて、私が使用してことをお勧め を進める完了したらasync library

ようになり、あなたのコード: async.map(array,(entry,callback) => validateBooking.bookingClash(entry,callback),(error,mappingResults)=>{...})

2)あなたは、再帰的にこの機能を変更しようとすることができone

`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

1

宣言以外は何も変更する必要はありません.Varの代わりにletを使用すると、ループが機能するはずです。

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

関連する問題