【问题标题】:Removing Attribute from JavaScript Object, Returned by Mongoose's "findOneAndUpdate" Method从 JavaScript 对象中删除属性,由 Mongoose 的“findOneAndUpdate”方法返回
【发布时间】:2013-09-18 10:54:09
【问题描述】:

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

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

但是,我不希望返回所有用户数据。具体来说,我想省略 _idpassword 字段。由于 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;

为了清楚起见,Envelope(在本例中为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"}}

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

谢谢!

【问题讨论】:

    标签: javascript node.js mongoose


    【解决方案1】:

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

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

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

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

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

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

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

    // 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;
    }
    

    请注意,在 cmets OP 报告中,成功地为 _id 执行了 select: false。如果这没有问题,那是一个很好的干净解决方案。我没试过,但我担心它会破坏一些东西。

    【讨论】:

    • 另外,为了补充一点,我最终在模式中明确创建了一个“_id”属性,并将“select”属性更改为 false,就像你对“passwordHash”属性所做的一样.
    • 要添加多个,在第二个参数中用空格分隔它们:'+prop1 +prop2'
    • callback() 是在哪里定义的?
    【解决方案2】:

    调用返回的user 参数是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));
    

    【讨论】:

    • +1 我没有意识到toObject() 的存在,我们在找到它之前使用的是JSON.parse(JSON.stringify(obj));
    • 天哪。将我的对象(?)转换为对象就可以了。不真实,但它有效!我本可以在这上面度过一个星期。非常感谢:)
    • 有效!只是提到它必须在每个结果中完成,例如:obj = results[i].toObject(); 其中i 是循环的索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 2010-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多