【问题标题】:$unset on multiple fields in mongodbmongodb 中多个字段的 $unset
【发布时间】:2020-09-23 21:28:30
【问题描述】:

假设我在 mongoDB 中有一个集合,如下所示 -

{
name : "Abhishek",
Roll_no : null,
hobby : stackoverflow
},
{
name : null,
Roll_no : 1,
hobby : null
}

现在我想删除我的文档中字段值为空的字段。我知道我可以通过以下方式使用$unset 来做到这一点-

db.collection.updateMany({name: null}, { $unset : { name : 1 }});

我们可以用同样的方式来处理爱好和姓名字段。

但我想知道是否可以只使用一个查询来执行相同的删除操作?我想知道是否可以使用$or 或其他东西来实现相同的效果,但只需一个命令。

有什么想法吗?

【问题讨论】:

  • 你的数据库版本是多少?
  • 4.0.15 但考虑我可以将其更新到最新版本。
  • 好的,如果你可以升级到4.2,你会有更好的选择来处理它..

标签: database mongodb mongoose mongodb-query


【解决方案1】:

在 MongoDB 版本上 >= 3.2

您可以利用.bulkWrite()

let bulkArr = [
  {
    updateMany: {
      filter: { name: null },
      update: { $unset: { name: 1 } }
    }
  },
  {
    updateMany: {
      filter: { Roll_no: null },
      update: { $unset: { Roll_no: 1 } }
    }
  },
  {
    updateMany: {
      filter: { hobby: null },
      update: { $unset: { hobby: 1 } }
    }
  },
];

/** All filter conditions will be executed on all docs
 *  but respective update operation will only be executed if respective filter matches (kind of individual ops) */
db.collection.bulkWrite(bulkArr);

参考: bulkwrite

在 MongoDB 版本上 >= 4.2

由于您想删除具有null 值的多个字段(其中字段名称无法列出或未知),请尝试以下查询:

db.collection.update(
  {}, // Try to use a filter if possible
  [
    /** 
     * using project as first stage in aggregation-pipeline
     * Iterate on keys/fields of document & remove fields where their value is 'null'
     */
    {
      $project: {
        doc: {
          $arrayToObject: { $filter: { input: { $objectToArray: "$$ROOT" }, cond: { $ne: ["$$this.v", null] } } }
        }
      }
    },
    /** Replace 'doc' object as root of document */
    {
      $replaceRoot: { newRoot: "$doc" }
    }
  ],
  { multi: true }
);

测试: mongoplayground

参考: update-with-an-aggregation-pipeline , aggregation-pipeline

注意:

我相信这将是一次性操作,将来您可以使用Joi npm 包或猫鼬模式验证器来限制将null 写入字段值。如果您可以列出您的字段名称,就好像没有太多加上数据集大小太高,那么请尝试使用 $$REMOVE 的聚合,正如“@thammada”所建议的那样。

到目前为止,.updateMany() 中的聚合管道不受许多客户端的支持,即使是少数 mongo shell 版本 - 当时我的票通过使用 .update() 解决了,如果它不起作用,请尝试使用update + { multi : true }.

【讨论】:

  • 我很好奇,.updateMany() 中的聚合管道是否也受到常规聚合管道的内存限制,是否有类似的方法来允许磁盘使用?
  • @thammada : 不确定,但总的来说,我相信.update() 中使用的阶段可能不是问题,因为大多数时候你在尝试积累文档,例如使用$group$sort 进行计算。
【解决方案2】:

使用 MongoDB v4.2,您可以使用 Updates with Aggregation Pipeline 以及 $$REMOVE 系统变量

db.collection.updateMany({ 
  $or: [{
    name: null
  }, {
    Roll_no: null
  }, {
    hobby: null
  }]
}, [{
  $set: {
    name: { $ifNull: ["$name", "$$REMOVE"] }
    Roll_no: { $ifNull: ["$Roll_no", "$$REMOVE"] },
    hobby: { $ifNull: ["$hobby", "$$REMOVE"] }
  }
}]

【讨论】:

    猜你喜欢
    • 2019-02-13
    • 2021-12-02
    • 2018-07-26
    • 1970-01-01
    • 2017-02-12
    • 2015-09-14
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    相关资源
    最近更新 更多