2015-05-01 49 views
1

我有演員和電影的MongoDB模型。這兩個型號的貓鼬模式是如下:根據Mongodb中的鍵和引用對象刪除重複項?

var ActorsSchema = new Schema({ 
    id : { 
     type : Number 
    }, 
    known_for:[{ 
     type: Schema.Types.ObjectId, 
     ref: 'Movie' 
    }] 
}) 

var MovieSchema = new Schema({ 
    genres: [{ 
     type: Schema.Types.ObjectId, 
     ref: 'Genre' 
    }], 
    id: { 
     type: Number 
    } 
}); 

known_for屬性角色模型包含參照其中該演員曾出演過的電影名單。

我想刪除重複的行爲人記錄,這將使用id fieled(不是_id)確定。但我也想做的是刪除known_for字段中已刪除的actor的記錄中引用的電影,並將其刪除,並且我想從Mongo界面執行此操作,因爲這些文檔中的記錄數非常大,並且正在執行此功能以編程方式將是時間效率低下。

我查看了相關的question,但它不適用於那些參考其他模型的模型。

+1

要清楚,你想級聯刪除存儲在Actor記錄的'known_for'數組中的ObjectIds的相關電影記錄?在這種情況下,任何引用該Movie的其他Actor將在其「known_for」數組中擁有一個孤立的ID。你是否總是想要執行這個邏輯,或者只是爲了有'id'值重複的Actor? –

回答

1

考慮使用聚合框架來識別重複文檔,獲取actors集合旁的actors集合副本_ids的列表,並以ids數組作爲查詢來發出刪除和更新命令。

出於測試目的,假設您在您的收藏以下數據(最低試驗情況下,當然演示目的):

db.movies.insert([ 
    { 
     "_id" : ObjectId("5543e79e42063d2be5d2ea84"), 
     "id" : 1, 
     "genres" : [] 
    }, 
    { 
     "_id" : ObjectId("5543e79e42063d2be5d2ea85"), 
     "id" : 2, 
     "genres" : [] 
    }, 
    { 
     "_id" : ObjectId("5543e79e42063d2be5d2ea86"), 
     "id" : 3, 
     "genres" : [] 
    } 
]); 

db.actors.insert([ 
    { id: 1, known_for: [ObjectId("5543e79e42063d2be5d2ea84")] }, 
    { id: 1, known_for: [ObjectId("5543e79e42063d2be5d2ea84")] }, 
    { id: 2, known_for: [ObjectId("5543e79e42063d2be5d2ea84"), ObjectId("5543e79e42063d2be5d2ea85")] }, 
    { id: 3, known_for: [ObjectId("5543e79e42063d2be5d2ea85"), ObjectId("5543e79e42063d2be5d2ea86")] } 
]); 

現在到了神奇的一部分。聚合管道將演員文檔按id分組,計算分組計數,創建兩個數組字段,用於保存演員_id重複項和電影對象ID。這條管道將結果輸出到集合愚弄稍後將在用於去除重複:

db.actors.aggregate([ 
    { 
     "$group": { 
      "_id": "$id", 
      "duplicates": { "$addToSet": "$_id" }, 
      "movies": { "$addToSet": "$known_for"}, 
      "count": { "$sum": 1 } 
     } 
    }, 
    { 
     "$match": { 
      "count": { "$gt": 1 } 
     } 
    }, 
    { 
     "$out": "dupes" 
    } 
]) 

詢問受騙者集合會給結果:

/* 1 */ 
{ 
    "_id" : 1.0000000000000000, 
    "duplicates" : [ 
     ObjectId("5543fc8e42063d2be5d2eaa2"), 
     ObjectId("5543fc8e42063d2be5d2eaa1") 
    ], 
    "movies" : [ 
     [ 
      ObjectId("5543e79e42063d2be5d2ea84") 
     ] 
    ], 
    "count" : 2 
} 

現在最有趣的部分。使用系列集合,然後從演員集合中刪除該系列。正如你從受騙者集合注意到,在電影字段是一個數組的數組,所以你需要將其鋪平,用扁平陣列,然後再消除電影和拉從演員集合孤立的電影引用:

db.dupes.find({}).find({}).forEach(function (doc) { 
    var movie_dupes = [];  
    db.actors.remove({ "_id": { "$in": doc.duplicates } });  

    doc.movies.forEach(function (arr){ 
     arr.forEach(function (id){ 
      movie_dupes.push(id) 
     });  
    }); 
    db.movies.remove({ "_id": { "$in": movie_dupes } }); 
    db.actors.update({ "known_for": { "$in": movie_dupes } }, { "$pull": { "known_for": { "$in": movie_dupes } } }, { "multi": true });  

}); 

日誌安慰:

Removed 2 record(s) in 38ms 
Removed 1 record(s) in 2ms 
Updated 1 existing record(s) in 1ms 

我們驗證我們的重複是否被沖掉:

db.actors.find() 

/* 1 */ 
{ 
    "_id" : ObjectId("5543fc8e42063d2be5d2eaa3"), 
    "id" : 2, 
    "known_for" : [ 
     ObjectId("5543e79e42063d2be5d2ea85") 
    ] 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("5543fc8e42063d2be5d2eaa4"), 
    "id" : 3, 
    "known_for" : [ 
     ObjectId("5543e79e42063d2be5d2ea85"), 
     ObjectId("5543e79e42063d2be5d2ea86") 
    ] 
} 

演員id 1(這是一個副本)確實被刪除。

db.movies.find() 

/* 1 */ 
{ 
    "_id" : ObjectId("5543e79e42063d2be5d2ea85"), 
    "id" : 2, 
    "genres" : [] 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("5543e79e42063d2be5d2ea86"), 
    "id" : 3, 
    "genres" : [] 
} 

電影ObjectId("5543e79e42063d2be5d2ea84")被刪除。

+1

這工作完美。謝謝:) –

+0

不用擔心@HaseebJaved :-) – chridam

相關問題