从MongoDB删除重复项

您好,我有一个约500万的文件在mongodb(复制)每个文件的43个领域。 如何删除重复的文件。 我尝试了

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

运行这段代码我得到一个错误“errmsg”:“从索引生成的命名空间名称..

 { "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 } 

怎么能解决这个问题?

从MongoDB 2.6开始, “dropDups”语法用于索引创build已被“弃用”,并在MongoDB 3.0中被删除 。 在大多数情况下,这不是一个好主意,因为“删除”是任意的,任何“重复”都可以删除。 这意味着什么被“删除”可能不是你真正想要删除的东西。

无论如何,你正在运行一个“索引长度”的错误,因为这里的索引键的值将允许更长。 一般来说,在任何正常的应用程序中,你不是“指”索引43个字段。

如果你想从一个集合中删除“重复”,那么你最好的办法是运行一个聚合查询,以确定哪些文档包含“重复”的数据,然后循环通过该列表删除已经“唯一” _id来自目标集合的值。 这可以通过“批量”操作来实现最高的效率。

:我很难相信你的文件实际上包含43个“独特”字段。 “所有你需要的”很可能只是简单地确定那些使文件“独一无二”的领域,然后遵循如下所述的过程:

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

如果你的MongoDB版本低于2.6,并且没有批量操作,那么你可以在循环中使用标准的.remove() 。 还要注意.aggregate()在这里不会返回一个游标,循环必须变成:

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

但是请务必密切关注您的文档,并且只包含您希望成为分组_id一部分的“唯一”字段。 否则,你最终没有任何东西,因为那里没有重复。