2013-01-09 74 views
1

我有一個架構如下(簡化):試圖刪除在貓鼬子文檔給了我一個內部貓鼬錯誤

var Permission = new Schema({ 
    _id: String, // email address 
    role: String // "admin" or "member" 
}); 

var Org = new Schema({ 
    name: {type: String, index: {unique: true, dropDups: true}, trim: true}, 
    permissions: [Permission] 
}); 

一個例子文件將是這樣的:

{ 
    "name": "My Org", 
    "permissions" : [ 
    {"_id" : "[email protected]", "role" : "admin"}, 
    {"_id" : "[email protected]", "role" : "member"} 
    ] 
} 

我試圖刪除權限行之一,使用命令org.permissions.remove(req.params.email),如示於下面的上下文中:

exports.removePermissions = function(req, res) { 
    var name = req.params.name; 
    return Org 
    .findOne({name: name}) 
    .select() 
    .exec(function(err, org) { 
     if (err) return Org.handleError(res, err); 
     if (!org) return Org.handleError(res, new Error("#notfound " + name)); 
     org.permissions.remove(req.params.email); 
     org.save(function(err, org) { 
     if (err) return Org.handleError(res, err); 
     else return res.send(org); 
     }); 
    }); 
}; 

當我這樣做,我得到以下錯誤:

TypeError: Cannot use 'in' operator to search for '_id' in [email protected] 
    at EmbeddedDocument.Document._buildDoc (/../node_modules/mongoose/lib/document.js:162:27) 
    at EmbeddedDocument.Document (/../node_modules/mongoose/lib/document.js:67:20) 
    at EmbeddedDocument (/../node_modules/mongoose/lib/types/embedded.js:27:12) 
    at new EmbeddedDocument (/../node_modules/mongoose/lib/schema/documentarray.js:26:17) 
    at MongooseDocumentArray._cast (/../node_modules/mongoose/lib/types/documentarray.js:62:10) 
    at Object.map (native) 
    at MongooseDocumentArray.MongooseArray.remove (/../node_modules/mongoose/lib/types/array.js:360:21) 
    at model.Org.methods.removePermissions (/../models/org.js:159:20) 

我能想到的唯一的事情就是貓鼬不支持_id字段不是對象ID的?這很奇怪,因爲我在代碼中的其他地方使用了它們,並且工作正常(例如org.permissions.id(「[email protected]」))。

任何建議非常感謝!

回答

10

我不知道爲什麼使用remove有沒有工作,但你可以findOneAndUpdate原子做到這一點和$pull操作:

exports.removePermissions = function(req, res) { 
    var name = req.params.name; 
    return Org.findOneAndUpdate(
    {name: name}, 
    {$pull: {permissions: {_id: req.params.email}}}, 
    function(err, org) { 
     // org contains the updated doc 
     ... 
    }); 
}; 
+0

再次 - 謝謝!我將這個remove()問題添加到Github上的mongoosejs問題列表中:https://github.com/LearnBoost/mongoose/issues/1278 –

+2

現在問題已經修復了......但它仍然處於預發佈階段,3.6科。雖然它是一個有點大的bug ...似乎我做出了不好的選擇,在平原蒙戈上選擇貓鼬...... – Marius

+0

感謝您的支持,讓這個操作變得非常棒。唯一的問題是你不知道'$ pull'操作是否成功,即,如果DB中有一個Permission對象被刪除了。對於這個錯誤檢查級別,你需要用'findById'分兩步完成,然後在結果返回的'org'上進行操作。 – fiznool

3

按照this answer,你需要調用remove()的子文檔你想刪除,而不是整個子文檔數組。

所以,變化:

org.permissions.remove(req.params.email); 

到:

org.permissions.id(req.params.email).remove(); 

這兩步法擁有的,你可以驗證的子文檔是否真正刪除它之前就存在answer supplied by @JohnnyHK的額外優勢。如果你想發送一個404響應來指示子文檔不存在 - 這一點很有用 - 據我所知,這不可能使用$ pull原子操作符。

請注意,如果您的子文檔數組有一個模式,這也只會工作,如問題所示。如果不是,或者它的模式類型爲Mixed,則從數據庫返回的集合將是一個普通數組而不是Mongoose增強型數組。這意味着沒有.id()函數。在這種情況下,我會用lodash#remove代替:

_.remove(org.permissions, (function(permission) { 
    return permission._id.toString() === req.params.email; 
})); 
+0

感謝您指出兩個選項!必須注意的是,必須保存頂級文檔才能保持子文檔的刪除。在這種情況下用'org.save()'。 –