mongodb 中多个字段的 $unset

Posted

技术标签:

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

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


name : "Abhishek",
Roll_no : null,
hobby : ***
,

name : null,
Roll_no : 1,
hobby : null

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

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

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

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

有什么想法吗?

【问题讨论】:

你的数据库版本是多少? 4.0.15 但考虑我可以将其更新到最新版本。 好的,如果你可以升级到4.2,你会有更好的选择来处理它.. 【参考方案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"] 
  
]

【讨论】:

以上是关于mongodb 中多个字段的 $unset的主要内容,如果未能解决你的问题,请参考以下文章

MongoDb:如何根据每个字段的值更新多个文档中的字段值?

kettle的mongodb输入多个字段想加

mongodb 怎么对多个字段模糊查询

使用 mongoose 在 mongodb 中保存多个字段数组

MongoDB:匹配字符串字段中的多个值

MongoDB - 具有多个字段并获得最新结果