21

我正在 Node.js 上用 JavaScript 编写一个简单的服务器,它(除其他外)允许用户管理他们的帐户(基本的 CRUD 功能等)。服务器连接到一个 MongoDB 实例,使用 Mongoose 来管理连接和数据。

Mongoose 中的模型有一个名为 的方法findOneAndUpdate(),它完全按照您的想法执行:查询数据库以获取返回的第一个文档,并根据您传递的参数更新所述文档。然后它将新的、更新的文档返回给用户。它完全按预期工作,我对此没有任何问题。

但是,我不希望返回所有用户数据。具体来说,我想省略_idandpassword字段。由于 MongoDB 返回的对象是一个基本的 JavaScript 对象,我假设我可以通过调用delete object.attribute. 不幸的是,由于某种原因,这不起作用。

这是我更新用户信息的代码:

case "update":
  User.findOneAndUpdate({"token": header.token}, body, function(err, user) {
    if (err) {
      return callback(err);
    } else {
      delete user["_id"];
      delete user["password"];
      return callback(null, new SuccessEnvelope(user));
    }
  });
  break;

为清楚起见, an Envelope(在本例中为 a SuccessEnvelope)是客户端和服务器为了促进通信而需要的一组信息。类似于 TCP 数据包。总之,我离题了...

例如,如果我想将我的用户名从“joe_bob”更新为“jim_bob”,我会将其发送到服务器:

{"header": "type": "user", "method": "update", "token": "IM_A_TOKEN_GAIS_SRSLY"}, "body": {"username": "jim_bob"}}

虽然用户的用户名更新成功,但这是我得到的回报:

{"header": {"type": "success"}, "body": {"__v": 0, "_id":"SOME_NUMERICAL_ID", "email": "joe_bob@email.com", "password": "SUPER_SECURE_PASSWORD_HASH_COME_AT_ME_NSA", "token": "IM_A_TOKEN_GAIS_SRSLY", "username": "jim_bob"}}

如您所见,_id并且password仍然存在。我究竟做错了什么?任何帮助将不胜感激。

谢谢!

4

2 回答 2

58

从调用返回的user参数是 a 的实例Model,在本例中为User.

如果您想将其用作原始 JavaScript 对象,则需要使用toObject. 这将返回一个普通的 JavaScript 对象。有了它,您可以使用delete和删除您想要的任何属性。

user = user.toObject(); // swap for a plain javascript object instance
delete user["_id"];
delete user["password"];
return callback(null, new SuccessEnvelope(user));
于 2013-09-13T18:01:14.077 回答
55

在通常不需要的属性的架构中设置 select: false

mongodb 允许查询指定数据库应该在响应对象中发回哪些属性。Mongoose 支持这一点,包括显式字段列表以及在模式中每个属性都可以默认选择或不选择的概念。因此,对于这个用例,最好的办法是默认将您的密码字段设置为取消选择:

var userSchema = new mongoose.Schema({
  passwordHash: {type: String, select: false}
  ...
});

然后你知道它永远不会自动回来。但是,当您实际处理登录请求时,您确实需要它,在这种情况下,您明确请求它:

User.findOne({email: theEmail}, '+passwordHash', callback);

对于烦人的 _id 属性,使用模式转换

_id 的事情让很多人头疼。Mongoose 直接在文档中解决了这个问题:

// specify the transform schema option
if (!schema.options.toObject) schema.options.toObject = {};
schema.options.toObject.transform = function (doc, ret, options) {
  // remove the _id of every document before returning the result
  delete ret._id;
}

请注意,在评论中 OP 报告成功select: false_id. 如果这没有问题,那是一个很好的干净解决方案。我没试过,但我担心它可能会破坏一些东西。

于 2013-09-13T17:53:32.367 回答