2012-06-05 147 views
2

我有一個名爲應用模型:貓鼬驗證競賽條件?

function uniqueName(name) 
{ 
console.log('In Unique Name function'); 
Application.find({}, function(error, documents) { 
    for(var i = 0; i < documents.length; i++) { 
     if(documents[i].name == name) { 
      console.log('About to return false'); 
      return false; 
     } 
    } 
}); 
return true; 
} 

後來在代碼中,我把一些數據模型,並將其保存:

var ApplicationSchema = new mongoose.Schema({ 
name  : {type: String, validate: [uniqueName, 'Unique Name']}, 
dateCreated: Date, 
containers : [ContainerSchema] 
}); 
mongoose.model('Application', ApplicationSchema); 
var Application = database.model('Application'); 

它時,它可以節省調用名爲uniqueName驗證功能:

newApplication.name = request.body.name; 
newApplication.save(function(error) { 
    console.log('Callback for save'); 
    if(error) { 
     console.log('error if statement'); 
     response.statusCode = 409; 
     response.end(); 
    } 
    console.log('Done with callback'); 
}); 
response.statusCode = 201; 
response.end(); 

當我測試這與不是唯一的一個名字,我得到一個201響應,並從我的終端輸出如下:

In Unique Name function 
Callback for save 
Done with callback 
About to return false 

我做錯了什麼,或者這真的是在Mongoose中的競爭條件?

回答

0

當你的驗證器是異步的(因爲它在這裏)它需要接受第二個參數,這個參數是一個回調函數,你必須調用true或false,這取決於驗證是否通過。所以:

function uniqueName(name, callback) 
{ 
    Application.find({}, function(error, documents) { 
     for(var i = 0; i < documents.length; i++) { 
      if(documents[i].name == name) { 
       return callback(false); 
      } 
     } 
     return callback(true); 
    } 
} 

但是,這不是很有效率;您應該:

篩選您的find而不是獲取所有文檔並手動搜索它們。例如

Application.find({name: name} ... 

甚至更​​好:

name創建唯一索引,讓蒙戈確保唯一性爲您服務。例如

var ApplicationSchema = new mongoose.Schema({ 
    name: {type: String, unique: true}, 
    ... 
+1

謝謝!你是對的,我沒有意識到有一個獨特的索引。 – amandawulf

+0

您應該強調獨特索引如何纔是解決此問題的唯一方法。在這樣的驗證器中進行查找會導致競爭狀況。在驗證器中的查找返回給您之後,可以使用'name'的相同值將另一個文檔插入到集合中。您的文檔仍然會通過驗證並繼續寫入,從而導致兩個文件具有相同的「name」值。 MongoDB獨特的索引保證這不會發生(只要您在保存時不禁用索引檢查)。 – binki