我正在使用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();
答案 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
});