使用Mongoose从MongoDB文档中删除一个键

162
我将使用Mongoose库来访问MongoDB与node.js相关的内容。
是否有一种方法可以从文档中删除一个键?即不仅将值设置为null,而是将其删除?
User.findOne({}, function(err, user){
  //correctly sets the key to null... but it's still present in the document
  user.key_to_delete = null;

  // doesn't seem to have any effect
  delete user.key_to_delete;

  user.save();
});

1
我以为我找到了,但经过一些测试:可能不是。不过这个链接有一些关于这个主题的好讨论。http://groups.google.com/group/mongoose-orm/browse_thread/thread/6053e3b8d4fe9098 - Stephen
算了,我猜这是你的帖子! - Stephen
11个回答

244

在早期版本中,您需要使用node-mongodb-native驱动程序。每个模型都有一个包含所有node-mongodb-native提供的方法的集合对象。因此,您可以通过以下方式执行所需操作:

User.collection.update({_id: user._id}, {$unset: {field: 1 }});

从2.0版本开始,您可以这样做:

User.update({_id: user._id}, {$unset: {field: 1 }}, callback);

自2.4版本以来,如果您已经有一个模型实例,您可以这样做:

doc.field = undefined;
doc.save(callback);

4
要么使用 User.update({ _id: id }, { $unset: { field: 1 }}, callback),要么如果您有一个文档实例,将路径设置为 undefined 并保存它:doc.field = undefined; doc.save() - aaronheckmann
33
请注意,如果你试图移除一个在你的模式中不再定义的旧属性,你需要执行 doc.set('field', undefined) - evilcelery
3
删除 doc.field.foo 怎么样? - chovy
34
@evilcelery 如果启用了严格模式(默认情况下),使用 doc.set('field', undefined) 可能不够,因为它不允许设置不再模式中的字段。 可以使用 doc.set('field', undefined, { strict: false }) - Alexander Link
1
没有其他评论有效。应该是这样的: User.updateOne({ _id: user._id }, { $unset: { field: 1 }}, { strict: false }) - undefined
显示剩余7条评论

73

您需要执行以下操作:

User.findOne({}, function(err, user){
  user.key_to_delete = undefined;
  user.save();
});

4
那只会将其设置为null,而不是OP所要求的内容。 - Ian Henry
30
从版本2.4.0开始,将文档键设置为undefined将传递$unset到mongodb。http://aaronheckmann.posterous.com/mongoose-240 - James Moore

52

我使用mongoose,并使用上述任何函数都无法满足我的需求。该函数可以编译无误,但字段仍然保持不变。

user.set('key_to_delete', undefined, {strict: false} );

对我起了作用。


点赞这个有用的回答,可惜@alexander-link在2015年没有将其作为答案(https://dev59.com/Hm855IYBdhLWcg3wMBPV#8qygEYcBWogLw_1beHyl) - w00t
1
谢谢你的回答,对我来说,其他解决方案在嵌套在数组中的对象上没有起作用! - BenSower
@BenSower 这也是我的情况。只有这个解决方案很好,因为我必须在找到特定文档的ID后删除一个带有数组的字段。 - Luis Febro
1
请注意,该字符串是到键的路径。因此,如果要删除的对象是嵌套的,则必须对其进行路径设置。 这个答案解决了我的问题! - Bradyo

11

删除Mongo中的某个键需要按照以下语法执行:

{ $unset : { field : 1} }

看起来在Mongoose中也是一样的。

编辑

请查看这个示例。


你能澄清这个答案并给出一个与上面示例代码相关的代码示例吗? - Daniel Beardsley
抱歉,我不熟悉Mongoose。上面的语法是Mongo语法,所以我认为任何编程语言对于此都应该有支持的驱动程序。我找到了一些例子,在我的回答中进行了检查。 - Andrew Orsich

3
如果你想从集合中删除一个键,请尝试这个方法。最初的回答。
 db.getCollection('myDatabaseTestCollectionName').update({"FieldToDelete": {$exists: true}}, {$unset:{"FieldToDelete":1}}, false, true);

我不认为这个问题是关于从集合中的所有文档中删除字段的,这就是这个操作所做的。 - taxilian

2

尝试:

User.findOne({}, function(err, user){
  // user.key_to_delete = null; X
  `user.key_to_delete = undefined;`

  delete user.key_to_delete;

  user.save();
});

1

Mongoose文档不是普通的JavaScript对象,这就是为什么您无法使用delete运算符(或来自'lodash'库的unset)的原因。

您的选择是将doc.path设置为null || undefined,或者使用Document.toObject()方法将mongoose doc转换为普通对象,然后像通常一样使用它。 在mongoose api-ref中阅读更多信息: http://mongoosejs.com/docs/api.html#document_Document-toObject

示例可能如下所示:

User.findById(id, function(err, user) {
    if (err) return next(err);
    let userObject = user.toObject();
    // userObject is plain object
});

1

这可能是一个类似于使用的问题

function (user)

替代

function(err, user)

针对查找的回调函数?我只是想帮忙,因为我已经遇到过这种情况。


1

所有这些答案的问题在于它们只适用于一个字段。例如,假设我想从我的文档中删除所有空字符串""的字段。 首先,您应该检查字段是否为空字符串,将其放入$unset

function unsetEmptyFields(updateData) {
  const $unset = {};
  Object.keys(updatedData).forEach((key) => {
    if (!updatedData[key]) {
      $unset[key] = 1;
      delete updatedData[key];
    }
  });
  updatedData.$unset = $unset;

  if (isEmpty(updatedData.$unset)) { delete updatedData.$unset; }

  return updatedData;
}

function updateUserModel(data){
const updatedData = UnsetEmptyFiled(data);

    const Id = "";
    User.findOneAndUpdate(
      { _id: Id },
      updatedData, { new: true },
    );
}


-4

我认为,如果你想从一个集合中删除特定的字段,应该这样做:

User.remove ({ key_to_delete: req.params.user.key_to_delete});

1
不要这样做 - 这将从数据库中删除每个与该查询匹配的文档。这完全不是 OP 想要的。 - taxilian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接