node.js 从 JavaScript 对象中删除属性,由 Mongoose 的“findOneAndUpdate”方法返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18791616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:36:40  来源:igfitidea点击:

Removing Attribute from JavaScript Object, Returned by Mongoose's "findOneAndUpdate" Method

javascriptnode.jsmongoose

提问by Zach Dziura

I'm writing a simple server in JavaScript on Node.js, which (among other things) allows the user to manage their account (basic CRUD functionality, etc). The server is connected to a MongoDB instance, using Mongoose to manage the connection and data.

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

Models in Mongoose have a method called findOneAndUpdate(), which does exactly what you think it does: queries the database for the first document returned and updates said document based on parameters you passed. It then returns the new, updated document to the user. It works exactly as intended and I have no problem with it.

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

However, I don't want ALL of the user data returned. Specifically, I'd like to omit the _idand passwordfields. Since the object returned by MongoDB is a basic JavaScript object, I assumed that I'd be able to remove those attributes by calling delete object.attribute. Unfortunately, for some reason that's not working.

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

Here's my code that updates the user information:

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

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;

For clarity, an Envelope(in this case, a SuccessEnvelope) is a bundle of information that the client and server need in order to facilitate communication. Similar-ish to a TCP packet. Anyhow, I digress...

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

For example, if I wanted to update my username from "joe_bob" to "jim_bob", I'd send this to the server:

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

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

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

And while the user's username is updated successfully, this is what I get in return:

当用户的用户名更新成功时,这就是我得到的回报:

{"header": {"type": "success"}, "body": {"__v": 0, "_id":"SOME_NUMERICAL_ID", "email": "[email protected]", "password": "SUPER_SECURE_PASSWORD_HASH_COME_AT_ME_NSA", "token": "IM_A_TOKEN_GAIS_SRSLY", "username": "jim_bob"}}

{"header": {"type": "success"}, "body": {"__v": 0, "_id":"SOME_NUMERICAL_ID", "email": "[email protected]", "password": "SUPER_SECURE_PASSWORD_HASH_COME_AT_ME_NSA", "token": "IM_A_TOKEN_GAIS_SRSLY", "username": "jim_bob"}}

As you can see, _idand passwordare still there. What am I doing wrong? Any help would be greatly appreciated.

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

Thank you!

谢谢!

回答by WiredPrairie

The userparameter that is returned from the call is an instance of a Model, in this case, the User.

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

If you want to use it as a raw JavaScript object, then you'd need to convert it using toObject. This returns a plain-old JavaScript object. With that, you can use deleteand remove whatever properties you'd like.

如果要将其用作原始 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));

回答by Peter Lyons

Set select: false in the schema for properties usually not wanted

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

mongodb allows queries to specify which properties the database should send back in the response objects. Mongoose supports this with several things including explicit field lists as well as in the schemas the notion that each property can be selected by default or not. So for this use case the best thing to do is set your password field to deselected by default:

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

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

Then you know it will never come back automatically. However, when you actually go to process a login request you do need it, in which case you explicitly request it:

然后你知道它永远不会自动回来。然而,当你真正去处理一个登录请求时你确实需要它,在这种情况下你明确地请求它:

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

For the annoying _id property, use schema transforms

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

The _id thing causes lots of folks headaches. Mongoose addresses this directly in the documentation:

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

Note that in the comments OP reports successfully doing select: falsefor _id. If that works without issues, that's a nice clean solution. I haven't tried it, but I'm worried it may break some things.

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