Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

database - $unset on multiple fields in mongodb

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 }.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...