2013-08-02 25 views
8

Node.jsとMongoDBで一意のIDを見つける際に、MongoDBに既存のIDを問い合わせるwhileループを作成して、一意の値が見つかるまで試みます。 IDが既に使用されている場合は、Mongoが何も返さなくなるまで、数字が最後にインクリメントされます。不正なbreak文(Node.js)

一意のIDが見つかった場合のbreak;ステートメントを除き、すべて機能しています。 Node.jsのリターン:SyntaxError: Illegal break statement

コード:

db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){ 
    //if ID exists already 
    if (data.id){ 

     var uniqueNumber = 1; 

     while (1) { 

      var uniqueNum_string = uniqueNumber.toString(); 
      var newUnique = data.id + uniqueNum_string; 
      db.collection('landmarks').findOne({'id':newUnique}, function(err, data){ 

       if (data.id){ 
        uniqueNumber++; 
       } 

       else { 
        saveLandmark(newUnique); 
        break; 
       } 
      }); 
     } 
    } 

    else { 
     saveLandmark(uniqueIDer); 
    } 

}); 

私が間違っているのか?

EDIT:誰もがそれを必要とする場合

はここで非同期を使って固定コードです:)

 db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){ 

      if (data){ 
       var uniqueNumber = 1; 
       var newUnique; 

       async.forever(function (next) { 
        var uniqueNum_string = uniqueNumber.toString(); 
        newUnique = data.id + uniqueNum_string; 

        db.collection('landmarks').findOne({'id':newUnique,'world':worldVal}, function(err, data){ 
        if (data){ 
         console.log('entry found!'); 
         uniqueNumber++; 
         next(); 
        } 
        else { 
         console.log('entry not found!'); 
         next('unique!'); // This is where the looping is stopped 
        } 
        }); 
       }, 
       function() { 
        saveLandmark(newUnique); 
       }); 
      } 
      else { 
       saveLandmark(uniqueIDer); 
      } 
     }); 
+0

サイドノート:構文エラーが修正されると、アプリケーションがロックされます。非同期 '.findOne()'で同期 'while(1)'を使うことはできません。後者の場合、エンジンはアイドリング状態でなければなりません。 –

+0

一意のIDを見つける最も良い方法は何ですか? – alyx

+0

@ jrbaldwinn:コレクション内のすべてのオブジェクトに、追加するときに一意のIDが自動的に割り当てられていることを確かめてください。オブジェクトIDはちょっと大きくて醜いですが、クラスタなどでも複製される可能性は、スリムとnoneの間のどこかにあります。 :) – cHao

答えて

15

あなたbreak文はループの本体内ではありません。代わりに、関数の本体の内部に、つまりfindOneコールバックです。より明確にこれを確認するには、一時的にあなたのコールバックハンドラとして指定された関数を使用するために役立つことができます:

var cb = function(err, data){ 
    if (data.id){ 
     uniqueNumber++; 
    } 
    else { 
     saveLandmark(newUnique); 
     break; // not inside a loop! 
    } 
}; 

db.collection('landmarks').findOne({'id':uniqueIDer}, function(err, data){ 
    //if ID exists already 
    if (data.id){ 
     var uniqueNumber = 1; 
     while (1) { 
      var uniqueNum_string = uniqueNumber.toString(); 
      var newUnique = data.id + uniqueNum_string; 
      db.collection('landmarks').findOne({'id':newUnique}, cb); 
     } 
    } 
    else { 
     saveLandmark(uniqueIDer); 
    } 
}); 

今はかなり明確だコールバック関数本体内breakは、ループ内ではないこと!私はまた、uniqueNumbernewUniqueの値がもはや有効範囲にないので、別の方法で問題を解決しましたが、それは別の問題です。 :)ここで重要なことは、関数がコード内に "ハード"境界を導入し、純粋に言語の構文に基づいて見るのが難しいことです。これは、このコールバックスタイルのプログラミングが非常に面倒なことがある理由の1つです。

実際、コードでの最初の試みが示唆するよりも、これを行うことはずっと困難です。 findOneを繰り返し呼び出して(非同期的に)結果を分析すると、コールバックの任意の層を介して成功信号を渡す方法が必要になります。

優れたasyncライブラリ(例:https://github.com/caolan/async#whilst)を使用すると、これで助けが得られる場合があります。

+1

+1 for asyncを使用する – Owen

+0

とにかく非同期コードが絶対必要になるだろう。そう。 :) – cHao