使用MapReduce删除重复记录

时间:2011-04-03 15:40:47

标签: mongodb mapreduce

我正在使用MongoDB并需要删除重复记录。我有一个看起来像这样的列表集合:(简化)

[
  { "MlsId": "12345"" },
  { "MlsId": "12345" },
  { "MlsId": "23456" },
  { "MlsId": "23456" },
  { "MlsId": "0" },
  { "MlsId": "0" },
  { "MlsId": "" },
  { "MlsId": "" }
]

如果MlsId不是“”或“0”且另一个列表具有相同的MlsId,则列表是重复的。因此,在上面的示例中,需要删除第2和第4条记录。

我如何找到所有重复的商品并将其删除?我开始查看MapReduce,但找不到适合我案例的例子。

这是我到目前为止所做的,但它没有检查MlsId是“0”还是“”:

m = function () { 
    emit(this.MlsId, 1); 
} 

r = function (k, vals) { 
   return Array.sum(vals); 
} 

res = db.Listing.mapReduce(m,r); 
db[res.result].find({value: {$gt: 1}}); 
db[res.result].drop();

4 个答案:

答案 0 :(得分:2)

我没有使用过mongoDB但是我使用了mapreduce。我认为你在mapreduce函数方面走在正确的轨道上。要排除他0和空字符串,你可以在地图函数本身添加一个检查..类似

m = function () { 
  if(this.MlsId!=0 && this.MlsId!="") {    
    emit(this.MlsId, 1); 
  }
} 

并且reduce应该返回键值对。所以它应该是:

r = function(k, vals) {
  emit(k,Arrays.sum(vals);
}

在此之后,您应该在输出中有一组键值对,使得键是MlsId,值是此特定ID出现的thimes数。我不确定db.drop()部分。正如您所指出的,它很可能会删除所有MlsIds而不是仅删除重复的MlsIds。为了解决这个问题,也许你可以先调用drop(),然后重新创建一次MlsId。这对你有用吗?

答案 1 :(得分:2)

在mongodb中,您可以使用查询来限制传入的用于映射的文档。您可能希望为那些您不关心的人做到这一点。然后在reduce函数中,您可以忽略dup并仅为每个重复键返回一个文档。

虽然我对你的目标感到有些困惑。如果您只想查找重复项并删除除其中一项之外的所有副本,那么您只需在该字段上创建一个唯一索引并使用dropDups选项;创建索引的过程将删除重复的文档。保持索引将确保它不会再次发生。

http://www.mongodb.org/display/DOCS/Indexes#Indexes-DuplicateValues

答案 2 :(得分:-1)

您可以使用聚合操作删除重复项。放松,引入虚拟$ group和$ sum阶段并忽略下一阶段的计数。像这样的东西,

db.myCollection.aggregate([
 {
     $unwind: '$list'
 },
 {
    $group:{
   '_id':
       {
         'listing_id':'$_id', 'MlsId':'$list.MlsId'
       },
          'count':
       {
          '$sum':1
       }
      }
},
{
      $group:
       {
        '_id':'$_id.listing_id',
        'list':
         {
          '$addToSet':
           {
            'MlsId':'$_id.MlsId'
           }
         }
       }
}
]);

答案 3 :(得分:-1)

这就是我按照@harri的说法删除重复项的方法:

//contains duplicated documents id and numeber of duplicates 
db.createCollection("myDupesCollection")
res = db.sampledDB.mapReduce(m, r, { out : "myDupesCollection" });

// iterate through duplicated docs and remove duplicates (keep one) 
db.myDupesCollection.find({value: {$gt: 1}}).forEach(function(myDoc){
    u_id = myDoc._id.MlsId;
    counts =myDoc.value;
    db.sampledDB.remove({MlsId: u_id},counts-1); //if there are 3 docs, remove 3-1=2 of them
});