Come rimuovere i duplicati in base a una chiave in Mongodb?

Ho una collezione in MongoDB dove ci sono circa (~ 3 milioni di dischi). Il mio record di esempio sarà simile,

{ "_id" = ObjectId("50731xxxxxxxxxxxxxxxxxxxx"), "source_references" : [ "_id" : ObjectId("5045xxxxxxxxxxxxxx"), "name" : "xxx", "key" : 123 ] } 

Sto avendo molti record duplicati nella collezione che hanno lo stesso source_references.key . (Per duplicato intendo, source_references.key non l’ _id ).

Voglio rimuovere i record duplicati basati su source_references.key , sto pensando di scrivere del codice PHP per attraversare ogni record e rimuovere il record se esiste.

C’è un modo per rimuovere i duplicati nella riga di comando interna di Mongo?

    Se si è certi che il file source_references.key identifica i record duplicati, è ansible garantire un indice univoco con dropDups:true opzione di creazione dell’indice dropDups:true in MongoDB 2.6 o precedente:

     db.things.ensureIndex({'source_references.key' : 1}, {unique : true, dropDups : true}) 

    Ciò manterrà il primo documento univoco per ogni valore source_references.key e source_references.key tutti i documenti successivi che altrimenti causerebbero una violazione della chiave duplicata.

    Note importanti :

    • L’opzione dropDups stata rimossa in MongoDB 3.0 , quindi sarà richiesto un approccio diverso. Ad esempio, è ansible utilizzare l’aggregazione come suggerito su: MongoDB duplica i documenti anche dopo aver aggiunto una chiave univoca .
    • Qualsiasi documento che manca il campo source_references.key verrà considerato come avente valore null , quindi i documenti successivi che mancheranno il campo chiave verranno eliminati. È ansible aggiungere l’opzione di creazione degli indici sparse:true modo che l’indice si applichi solo ai documenti con un campo source_references.key .

    Attenzione ovvia : eseguire un backup del database e provare prima questo in un ambiente di gestione temporanea se si è preoccupati della perdita involontaria di dati.

    Questa è la query più semplice che ho usato sul mio MongoDB 3.2

     db.myCollection.find({}, {myCustomKey:1}).sort({_id:1}).forEach(function(doc){ db.myCollection.remove({_id:{$gt:doc._id}, myCustomKey:doc.myCustomKey}); }) 

    customKey tuo customKey prima di eseguirlo per aumentare la velocità

    Rimuovi i duplicati dal framework di aggregazione .

    un. Se si desidera eliminare in una volta.

     var duplicates = []; db.collectionName.aggregate([ // discard selection criteria, You can remove "$match" section if you want { $match: { source_references.key: { "$ne": '' } }}, { $group: { _id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties dups: { "$addToSet": "$_id" }, count: { "$sum": 1 } }}, { $match: { count: { "$gt": 1 } // Duplicates considered as count greater than one }} ]) // You can display result until this and check duplicates .forEach(function(doc) { doc.dups.shift(); // First element skipped for deleting doc.dups.forEach( function(dupId){ duplicates.push(dupId); // Getting all duplicate ids } ) }) // If you want to Check all "_id" which you are deleting else print statement not needed printjson(duplicates); // Remove all duplicates in one go db.collectionName.remove({_id:{$in:duplicates}}) 

    b. È ansible eliminare i documenti uno per uno.

     db.collectionName.aggregate([ // discard selection criteria, You can remove "$match" section if you want { $match: { source_references.key: { "$ne": '' } }}, { $group: { _id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties dups: { "$addToSet": "$_id" }, count: { "$sum": 1 } }}, { $match: { count: { "$gt": 1 } // Duplicates considered as count greater than one }} ]) // You can display result until this and check duplicates .forEach(function(doc) { doc.dups.shift(); // First element skipped for deleting db.collectionName.remove({_id : {$in: doc.dups }}); // Delete remaining duplicates }) 

    Mentre @ Stennie’s è una risposta valida, non è l’unico modo. Infatti il ​​manuale di MongoDB ti chiede di essere molto cauto mentre lo fai. Ci sono altre due opzioni

    1. Lascia che sia MongoDB a farlo usando Map Reduce
      • Un altro modo
    2. Lo fai programmaticamente che è meno efficiente.

    Ecco un modo leggermente più “manuale” per farlo:

    In sostanza, per prima cosa, ottieni un elenco di tutte le chiavi univoche che ti interessano.

    Quindi esegui una ricerca utilizzando ognuna di quelle chiavi ed elimina se quella ricerca ritorna più grande di una.

      db.collection.distinct("key").forEach((num)=>{ var i = 0; db.collection.find({key: num}).forEach((doc)=>{ if (i) db.collection.remove({key: num}, { justOne: true }) i++ }) }); 

    pip installa mongo_remove_duplicate_indexes

    1. crea uno script in qualsiasi lingua
    2. scorrere la tua collezione
    3. crea una nuova collezione e crea un nuovo indice in questa collezione con un set unico su true, ricorda che questo indice deve essere lo stesso dell’indice che desideri rimuovere i duplicati dalla tua collezione originale con lo stesso nome per avere una collezione di giochi, e in questo collezione hai un genere di campo che contiene duplicati che vuoi rimuovere, quindi crea solo una nuova collezione db.createCollection (“cname”) crea un nuovo indice db.cname.createIndex ({‘genere’: 1}, unico: 1) adesso quando si inserirà un documento con un genere simile, verrà accettato solo il primo, l’altro verrà rifiutato con l’errore della chiave duplicae
    4. ora basta inserire i valori in formato json ricevuti nella nuova raccolta e gestire l’eccezione usando la gestione delle eccezioni per ex pymongo.errors.DuplicateKeyError

    controlla il codice sorgente del pacchetto per mongo_remove_duplicate_indexes per una migliore comprensione

    Se hai abbastanza memoria, puoi in scala fare qualcosa del genere:

     cole.find().groupBy(_.customField).filter(_._2.size>1).map(_._2.tail).flatten.map(_.id) .foreach(x=>cole.remove({id $eq x})