修复 MongoDB 中包含相同字段的记录

fix records that contain the same field in MongoDB

由于系统错误,创建了不正确的记录。

当前:

{
   "_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
}

我要:

{
   "_id" : ObjectId("5cb48b1875aca0626d0272db"),
   "similiarModels" : [
                 ObjectId("9fg48f5325qwa0436h9433ae")
    ]
}

这是一个解决方案。注意管道形式 update$$REMOVE 特殊值的使用。

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

或者,可以使用 v4.4 中引入的“合并到自身”功能。这让aggregate可以充当巨人update。请参阅以下评论中的警告:

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

]);