2013-08-02 142 views
1

根據以前的問題Illegal break statement (Node.js)的建議,我實現了async.whilst(),但它不會迭代多次。Node.js - 異步雖然循環不迭代

我想通過在ID末尾增加一個數字來查找唯一ID,然後查詢Mongo以查看該ID是否存在。如果不存在,則找到唯一ID。它只循環一次,而不是直到找到唯一。哪裏不對?

代碼:

var uniqueNumber = 1; 
var newUnique; 

async.whilst(
    function() { 

     var uniqueNum_string = uniqueNumber.toString(); 
     newUnique = data.id + uniqueNum_string; 

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

      if (data){ 
       console.log('entry found!'); 
       return; 
      } 

      else { 
       console.log('entry not found!'); 

      } 
     }); 

    }, 
    function (callback) { 

    uniqueNumber++; 

    }, 
    function (err) { 

     saveLandmark(newUnique); 
    } 
); 
+0

我相信你必須在「entry not found」else語句中返回true才能再次循環。 –

+5

因爲測試函數應該是同步的,所以你不能真正使用。你也必須在迭代器中調用回調。 –

+0

好點@AndreasHultgren。我完全忽略了這一點。 –

回答

6

我不能真正找到適合這項任務了良好的異步功能,所以我砍死的東西一起使用async.forever()。該函數將繼續運行,直到你回調一個「錯誤」,這就是你想要做的。

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

關於你想要解決的問題,在我看來你想插入一個帶有唯一ID的新文檔。如果是這樣,你會經常這樣做,我會說這是一個非常低效的方法。如果數據庫中有一千個文檔,那麼在您接近唯一標識之前,您將對數據庫執行一千次完全無意義的請求。

更好的方法是從集合中獲取第一個按id排序的文檔(例如最高的id)。然後將該ID增加1並嘗試插入,直到它不被拒絕。因爲即使找到唯一的ID,在保存文檔時,另一個插入可能來自另一個客戶端或另一個實例(在負載平衡的情況下)。這可能會也可能不是您的問題,我對您的應用程序不夠了解,我只是認爲您應該瞭解當前方法和我的答案的缺點。

+0

作品!實際上,我試圖根據用戶提交的文檔名稱生成唯一的URL。我正在使用你的monguurl插件,但由於某種原因它沒有工作(在過去)。無論如何,系統中不應該有太多重複的東西,我需要......謝謝! – alyx

+0

酷,我會建議monguurl,如果你使用貓鼬......如果你認爲我的模塊有問題,請在github上創建一個問題:)現在當我想到它時,我實際上看到了一個神祕的'data.id',所以我想我的警告畢竟是不需要的,這正是我所做的事情(除了我插入而不是發現,你可能會或可能不會遇到問題,這取決於是否有可能在那兩個客戶端嘗試同時插入文檔)。 –

1

這樣呢?我沒有測試它,因爲我不知道你使用的是哪個數據庫模塊,但邏輯應該是顯而易見的。

function searchNubmersForResults(firstNumber, callback) { 
    //place other variables here, and you can collect the results within the closure, and send them as arguments to your callback 
    function testNumber(uniqueNumber) { 
     var uniqueNum_string = uniqueNumber.toString(); 
     newUnique = data.id + uniqueNum_string; 

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

      if (data){ 
       console.log('entry found!'); 
       callback(data);//We're done, use the callback on the data 
      } else { 
       console.log('entry not found!'); 
       testNumber(uniqueNumber++);//Launch the next test 
      } 
     }); 
    } 

    testNumber(firstNumber);//Laucn the first test 
} 

searchNubmersForResults(0, function(data) { 
    console.log('You have data now: ' + data); 
});