sql >> Base de Datos >  >> NoSQL >> MongoDB

Eliminar duplicados de MongoDB

Los "dropDups" La sintaxis para la creación de índices ha quedado "en desuso" a partir de MongoDB 2.6 y se eliminó en MongoDB 3.0. En la mayoría de los casos, no es una muy buena idea usar esto, ya que la "eliminación" es arbitraria y cualquier "duplicado" podría eliminarse. Lo que significa que lo que se "elimina" puede no ser lo que realmente desea eliminar.

De todos modos, se encuentra con un error de "longitud de índice" ya que el valor de la clave de índice aquí sería más largo de lo permitido. En términos generales, no está "destinado" a indexar 43 campos en ninguna aplicación normal.

Si desea eliminar los "duplicados" de una colección, su mejor opción es ejecutar una consulta de agregación para determinar qué documentos contienen datos "duplicados" y luego recorrer esa lista eliminando "todos menos uno" de los ya "únicos" _id valores de la colección de destino. Esto se puede hacer con operaciones "a granel" para lograr la máxima eficiencia.

NOTA :Me resulta difícil creer que sus documentos realmente contengan 43 campos "únicos". Es probable que "all you need" es simplemente identificar solo aquellos campos que hacen que el documento sea "único" y luego siga el proceso como se describe a continuación:

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

Si tiene una versión de MongoDB "inferior" a la 2.6 y no tiene operaciones masivas, puede probar con .remove() estándar dentro del bucle también. También notando que .aggregate() no devolverá un cursor aquí y el bucle debe cambiar a:

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

Pero asegúrese de mirar sus documentos de cerca y solo incluya "solo" los campos "únicos" que espera que formen parte de la agrupación _id . De lo contrario, no eliminará nada en absoluto, ya que no hay duplicados allí.