2016-02-29 18 views
6

Ho una raccolta con il campo chiamato "contact_id". Nella mia collezione ho registri duplicati con questa chiave.Rimuovi duplicato in MongoDB

Come posso rimuovere i duplicati, risultando in un solo registro?

Ho già provato:

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

ma non ha funzionato, perché i dropDups funzione non è più disponibile in MongoDB 3.x

sto usando 3.2

Grazie

risposta

18

Sì, dropDups è andato per sempre. Ma puoi sicuramente raggiungere il tuo obiettivo con un piccolo sforzo.

È necessario prima trovare tutte le righe duplicate e quindi rimuovere tutto tranne prima.

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

Come vedete doc.dups.shift() rimuoverà prima _id dalla matrice e quindi rimuovere tutti i documenti con il restante _ids in ordine dups.

script sopra rimuoverà tutti i documenti duplicati.

+0

cercherò di tornare a commentare se ha funzionato! Grazie – Jhonathan

+0

Sembra buono. Fammi sapere come va. – Saleem

+0

Ciao. Parziale lavorato Quando inserisco una piccola collezione funziona bene. Ma quando eseguo in una grande raccolta i database "bloccano" e altri interrogano va in timeout. – Jhonathan

0

forse è un buon tentativo di creare un tmpColection, creare un indice univoco, quindi copiare i dati dall'origine e l'ultimo passo saranno i nomi di scambio?

altra idea, ho dovuto è di ottenere indici in array (utilizzando aggregazione) e poi anello raddoppiato attraverso chiamando il metodo remove() con il parametro JUSTONE impostato su true o 1.

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

e fare array loop through ids ha senso per te?

5

questo è un buon modello per mongod 3+ che garantisce anche che non si eseguirà la nostra memoria che può accadere con collezioni davvero grandi. È possibile salvare questo in un file dedup.js, personalizzarlo ed eseguirlo sul database desiderato con: 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}});