2016-02-29 9 views
6

Mam kolekcję z polem o nazwie "contact_id". W mojej kolekcji mam zduplikowane rejestry z tym kluczem.Usuń duplikat w MongoDB

W jaki sposób mogę usunąć duplikaty, w wyniku czego powstaje tylko jeden rejestr?

Próbowałem już:

db.PersonDuplicate.ensureIndex({"contact_id": 1}, {unique: true, dropDups: true}) 

Ale nie działa, ponieważ dropDups funkcja nie jest już dostępna w MongoDB 3.x

Używam 3,2

Dzięki

Odpowiedz

18

Tak, dropDups zniknął na dobre. Ale z pewnością możesz osiągnąć swój cel przy odrobinie wysiłku.

Najpierw należy znaleźć wszystkie zduplikowane wiersze, a następnie usunąć wszystkie z wyjątkiem pierwszego.

db.dups.aggregate([{$group:{_id:"$contact_id", dups:{$push:"$_id"}, count: {$sum: 1}}}, 
{$match:{count: {$gt: 1}}} 
]).forEach(function(doc){ 
    doc.dups.shift(); 
    db.dups.remove({_id : {$in: doc.dups}}); 
}); 

Jak widać doc.dups.shift() usunie pierwszy _id z tablicy, a następnie usunąć wszystkie dokumenty z pozostałą _ids w dups tablicy.

Powyższy skrypt usunie wszystkie duplikaty dokumentów.

+0

Postaram i powrócić do komentowania, jeśli pracował! Dzięki – Jhonathan

+0

Brzmi nieźle. Daj mi znać jak idzie. – Saleem

+0

Witam. Częściowo działało. Po umieszczeniu w małej kolekcji działa dobrze. Ale kiedy wykonuję w dużym zbiorze, bazy danych "blokada" i inne zapytania trafiają do limitu czasu. – Jhonathan

0

może to być dobra próba utworzenia tmpColection, stworzenia unikalnego indeksu, a następnie skopiowania danych ze źródła, a ostatnim krokiem będą nazwy wymiany?

Inny pomysł, miałem to, aby język podwoiła indeksy tablicy (przy agregacji), a następnie pętli thru wywołanie metody remove() z parametrem justone ustawiony na true lub 1.

var itemsToDelete = db.PersonDuplicate.aggregate([ 
{$group: { _id:"$_id", count:{$sum:1}}}, 
{$match: {count: {$gt:1}}}, 
{$group: { _id:1, ids:{$addToSet:"$_id"}}} 
]) 

i dokonać pętla thru ids array ma to dla ciebie sens?

5

to dobry wzór dla mongody 3+, który gwarantuje, że nie uruchomisz pamięci, która może się zdarzyć w przypadku naprawdę dużych kolekcji. Można zapisać ten plik do dedup.js, dostosować go i uruchomić go na żądaną danych z: Mongo localhost: 27017/YOURDB dedup.js

var duplicates = []; 

db.runCommand(
    {aggregate: "YOURCOLLECTION", 
    pipeline: [ 
     { $group: { _id: { DUPEFIELD: "$DUPEFIELD"}, dups: { "$addToSet": "$_id" }, count: { "$sum": 1 } }}, 
     { $match: { count: { "$gt": 1 }}} 
    ], 
    allowDiskUse: true } 
) 
.result 
.forEach(function(doc) { 
    doc.dups.shift(); 
    doc.dups.forEach(function(dupId){ duplicates.push(dupId); }) 
}) 
printjson(duplicates); //optional print the list of duplicates to be removed 

db.YOURCOLLECTION.remove({_id:{$in:duplicates}});