Eliminar duplicados de MongoDB

hola Tengo ~ 5 millones de documentos en mongodb (replicación) cada documento 43 campos. cómo eliminar un documento duplicado lo intenté

db.testkdd.ensureIndex({ duration : 1 , protocol_type : 1 , service : 1 , flag : 1 , src_bytes : 1 , dst_bytes : 1 , land : 1 , wrong_fragment : 1 , urgent : 1 , hot : 1 , num_failed_logins : 1 , logged_in : 1 , num_compromised : 1 , root_shell : 1 , su_attempted : 1 , num_root : 1 , num_file_creations : 1 , num_shells : 1 , num_access_files : 1 , num_outbound_cmds : 1 , is_host_login : 1 , is_guest_login : 1 , count : 1 , srv_count : 1 , serror_rate : 1 , srv_serror_rate : 1 , rerror_rate : 1 , srv_rerror_rate : 1 , same_srv_rate : 1 , diff_srv_rate : 1 , srv_diff_host_rate : 1 , dst_host_count : 1 , dst_host_srv_count : 1 , dst_host_same_srv_rate : 1 , dst_host_diff_srv_rate : 1 , dst_host_same_src_port_rate : 1 , dst_host_srv_diff_host_rate : 1 , dst_host_serror_rate : 1 , dst_host_srv_serror_rate : 1 , dst_host_rerror_rate : 1 , dst_host_srv_rerror_rate : 1 , lable : 1 }, {unique: true, dropDups: true} ) 

ejecutar este código me sale un error “errmsg”: “namespace name generated from index ..

 { "ok" : 0, "errmsg" : "namespace name generated from index name \"project.testkdd.$duration_1_protocol_type_1_service_1_flag_1_src_bytes_1_dst_bytes_1_land_1_wrong_fragment_1_urgent_1_hot_1_num_failed_logins_1_logged_in_1_num_compromised_1_root_shell_1_su_attempted_1_num_root_1_num_file_creations_1_num_shells_1_num_access_files_1_num_outbound_cmds_1_is_host_login_1_is_guest_login_1_count_1_srv_count_1_serror_rate_1_srv_serror_rate_1_rerror_rate_1_srv_rerror_rate_1_same_srv_rate_1_diff_srv_rate_1_srv_diff_host_rate_1_dst_host_count_1_dst_host_srv_count_1_dst_host_same_srv_rate_1_dst_host_diff_srv_rate_1_dst_host_same_src_port_rate_1_dst_host_srv_diff_host_rate_1_dst_host_serror_rate_1_dst_host_srv_serror_rate_1_dst_host_rerror_rate_1_dst_host_srv_rerror_rate_1_lable_1\" is too long (127 byte max)", "code" : 67 } 

¿cómo puede resolver el problema?

La syntax “dropDups” para la creación de índices ha sido “obsoleta” a partir de MongoDB 2.6 y eliminada en MongoDB 3.0 . No es una buena idea en la mayoría de los casos usar esto ya que la “eliminación” es arbitraria y cualquier “duplicado” podría eliminarse. Lo que significa que lo que se “quita” puede no ser lo que realmente quieres eliminar.

De todos modos, se está ejecutando un error de “longitud de índice” ya que el valor de la clave de índice aquí sería más largo que el permitido. En general, 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” del _id ya “único” _id valores de la colección objective Esto se puede hacer con operaciones “masivas” para una máxima eficiencia.

NOTA : Me cuesta creer que sus documentos realmente contengan 43 campos “únicos”. Es probable que “todo lo que necesita” sea ​​simplemente identificar solo aquellos campos que hacen que el documento sea “único” y luego seguir 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, entonces puede probar con .remove() estándar dentro del bucle también. También observando 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 detenidamente sus documentos y solo incluya “solo” los campos “únicos” que espera formar parte de la agrupación _id . De lo contrario, terminas eliminando nada, ya que no hay duplicados allí.