问题
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