Incorrect records were created due to an error in the system.
Current :
{
"_id" : ObjectId("5cb48b1875aca0626d0272db"),
"similiarModels" : [
ObjectId("5cb48b1875aca0626d0272db"), -> the same as the _id field of the object, it must be removed from the array
ObjectId("9fg48f5325qwa0436h9433ae")
]
"topModel" : ObjectId("5cb48b1875aca0626d0272db") -> the same as the _id field of the object, should be removed
}
I want to :
{
"_id" : ObjectId("5cb48b1875aca0626d0272db"),
"similiarModels" : [
ObjectId("9fg48f5325qwa0436h9433ae")
]
}
CodePudding user response:
Here is a solution. Note the use of the pipeline form of update
and the $$REMOVE
special value.
db.foo.update(
{}, // no filter; get all docs
[ // use pipeline form of update expression for greater flexibility!
{$set: {
'similarModels': {$setDifference:['$similarModels', ['$_id'] ]},
'topModel': {$cond: [
{$eq:['$topModel','$_id']}, // if
'$$REMOVE', // then get rid of field
'$topModel' // else set it back to original
]}
}}
],
{multi:true}
);
Alternatively, one can use the "merge onto self" capability introduced in v4.4. This allows aggregate
to act as a giant update
. See caveat in comments below:
db.foo.aggregate([
// EXACT same expression as pipeline update above; nice.
{$set: {
'similarModels': {$setDifference: ['$similarModels', ['$_id'] ]},
'topModel': {$cond: [
{$eq:['$topModel','$_id']}, // if
'$$REMOVE', // then get rid of field
'$topModel' // else set it back to original
]}
}},
// Sadly, the whenMatched:'merge' option will not "unset" fields; it only
// adds or overwrites fields so this approach will not work for $topModel field.
// We can, however, use whenMatched:'replace' but this might present
// a performance issue because the entire doc, not just similarModels
// and topModel, is being written back.
{$merge: {
into: "foo",
on: [ "_id" ],
whenMatched: "replace",
whenNotMatched: "fail"
}}
]);