MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Rimuovi i duplicati da MongoDB

I "dropDups" la sintassi per la creazione dell'indice è stata "obsoleta" a partire da MongoDB 2.6 e rimossa in MongoDB 3.0. Non è una buona idea nella maggior parte dei casi utilizzarlo poiché la "rimozione" è arbitraria e qualsiasi "duplicato" potrebbe essere rimosso. Ciò significa che ciò che viene "rimosso" potrebbe non essere ciò che vorresti veramente rimuovere.

Ad ogni modo, stai riscontrando un errore di "lunghezza dell'indice" poiché il valore della chiave dell'indice qui sarebbe più lungo di quanto consentito. In generale, non sei "destinato" a indicizzare 43 campi in nessuna normale applicazione.

Se desideri rimuovere i "duplicati" da una raccolta, la soluzione migliore è eseguire una query di aggregazione per determinare quali documenti contengono dati "duplicati" e quindi scorrere l'elenco rimuovendo "tutti tranne uno" dei già "unici" _id valori dalla raccolta di destinazione. Questo può essere fatto con operazioni "bulk" per la massima efficienza.

NOTA :Trovo difficile credere che i tuoi documenti contengano effettivamente 43 campi "unici". È probabile che "tutto ciò di cui hai bisogno" è semplicemente identificare solo quei campi che rendono il documento "unico" e quindi seguono il processo come descritto di seguito:

var bulk = db.testkdd.initializeOrderedBulkOp(),
    count = 0;

// List "all" fields that make a document "unique" in the `_id`
// I am only listing some for example purposes to follow
db.testkdd.aggregate([
    { "$group": {
        "_id": {
           "duration" : "$duration",
          "protocol_type": "$protocol_type", 
          "service": "$service",
          "flag": "$flag"
        },
        "ids": { "$push": "$_id" },
        "count": { "$sum": 1 }
    }},
    { "$match": { "count": { "$gt": 1 } } }
],{ "allowDiskUse": true}).forEach(function(doc) {
    doc.ids.shift();     // remove first match
    bulk.find({ "_id": { "$in": doc.ids } }).remove();  // removes all $in list
    count++;

    // Execute 1 in 1000 and re-init
    if ( count % 1000 == 0 ) {
       bulk.execute();
       bulk = db.testkdd.initializeOrderedBulkOp();
    }
});

if ( count % 1000 != 0 ) 
    bulk.execute();

Se hai una versione di MongoDB "inferiore" alla 2.6 e non hai operazioni di massa, puoi provare con lo standard .remove() anche all'interno del ciclo. Notando anche che .aggregate() non restituirà un cursore qui e il ciclo deve cambiare in:

db.testkdd.aggregate([
   // pipeline as above
]).result.forEach(function(doc) {
    doc.ids.shift();  
    db.testkdd.remove({ "_id": { "$in": doc.ids } });
});

Ma assicurati di esaminare attentamente i tuoi documenti e di includere "solo" i campi "unici" che prevedi facciano parte del gruppo _id . Altrimenti finisci per non rimuovere nulla, poiché non ci sono duplicati lì.