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" : "joe@gmail.com", "role" : "admin"},
    {"_id" : "mary@gmail.com", "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 joe@gmail.com
    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)

我唯一能想到的是 Mongoose 不支持不是 ObjectID 的 _id 字段?这很奇怪,因为我在我的代码中的其他地方使用了这些并且它工作正常(例如 org.permissions.id("joe@gmail.com") 工作)。

任何建议都非常感谢!

4

2 回答 2

10

我不确定为什么使用removethere 不起作用,但您可以使用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
      ...
    });
};
于 2013-01-09T19:58:28.610 回答
3

根据这个答案,您需要调用remove()要删除的子文档,而不是整个子文档数组。

所以,改变:

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

到:

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

与@JohnnyHK 提供的答案相比,这种两步方法具有额外的优势,因为您可以在删除子文档之前验证子文档是否实际存在。如果您想发送指示子文档不存在的 404 响应,这将很有用 - 据我所知,使用 $pull 原子运算符是不可能的。

请注意,这也仅在您的子文档数组具有架构时才有效,如问题所示。如果不是,或者它的模式类型为Mixed,则从数据库返回的集合将是一个普通数组,而不是 Mongoose 增强数组。这意味着没有.id()功能。在这种情况下,我会使用lodash#remove代替:

_.remove(org.permissions, (function(permission) {
  return permission._id.toString() === req.params.email;
}));
于 2014-05-15T10:31:25.190 回答