$unset on multiple fields in mongodb

心已入冬 提交于 2020-07-03 00:45:10

问题


Suppose I have a collection in mongoDB like given below -

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

Now I want to delete the fields in my Documents where the field values are null. I know that I can do it using the $unset in following way -

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

And we could do it in the same way for hobby and name field.

But I was wondering if I can do the same deletion operation using just one query? I was wondering if maybe I could use $or or something else to achieve the same effect but in a single command.

Any ideas?


回答1:


On MongoDB version >= 3.2 :

You can take advantage of .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);

Ref : bulkwrite

On MongoDB version >= 4.2 :

Since you wanted to delete multiple fields(where field names can't be listed down or unknown) having null value, try below query :

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

Test : mongoplayground

Ref : update-with-an-aggregation-pipeline , aggregation-pipeline

Note :

I believe this would be one time operation & in future you can use Joi npm package or mongoose schema validators to restrict writing null's as field values. If you can list down your field names as if not too many plus dataset size is way too high then try to use aggregation with $$REMOVE as suggested by '@thammada'.

As of now, aggregation-pipeline in .updateMany() is not supported by many clients even few mongo shell versions - back then my ticket to them got resolved by using .update(), if it doesn't work then try to use update + { multi : true }.




回答2:


With MongoDB v4.2, you can do Updates with Aggregation Pipeline, along with the $$REMOVE system variable

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"] }
  }
}]


来源:https://stackoverflow.com/questions/62202373/unset-on-multiple-fields-in-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!