61

我在 MongoDB 中有一个集合,其中大约有(约 300 万条记录)。我的样本记录看起来像,

 { "_id" = ObjectId("50731xxxxxxxxxxxxxxxxxxxx"),
   "source_references" : [
                           "_id" : ObjectId("5045xxxxxxxxxxxxxx"),
                           "name" : "xxx",
                           "key" : 123
                          ]
 }

我在集合中有很多重复记录具有相同的source_references.key. (我的意思是重复,source_references.key而不是_id)。

我想删除基于的重复记录source_references.key,我正在考虑编写一些 PHP 代码来遍历每条记录并删除记录(如果存在)。

有没有办法删除 Mongo 内部命令行中的重复项?

4

8 回答 8

80

此答案已过时:dropDups选项已在 MongoDB 3.0 中删除,因此在大多数情况下需要采用不同的方法。例如,您可以按照以下建议使用聚合:MongoDB duplicate documents even after added unique key

如果您确定标识重复记录,您可以在 MongoDB 2.6 或更早版本中使用索引创建选项source_references.key确保唯一索引:dropDups:true

db.things.ensureIndex({'source_references.key' : 1}, {unique : true, dropDups : true})

这将为每个source_references.key值保留第一个唯一文档,并删除任何可能导致重复键违规的后续文档。

重要提示:任何缺少该source_references.key字段的文档都将被视为具有值,因此后续缺少该关键字段的文档将被删除。您可以添加sparse:true索引创建选项,以便索引仅适用于具有source_references.key字段的文档。

明显的警告:备份您的数据库,如果您担心意外的数据丢失,请先在暂存环境中尝试此操作。

于 2012-11-02T07:20:40.533 回答
67

这是我在 MongoDB 3.2 上使用的最简单的查询

db.myCollection.find({}, {myCustomKey:1}).sort({_id:1}).forEach(function(doc){
    db.myCollection.remove({_id:{$gt:doc._id}, myCustomKey:doc.myCustomKey});
})

在运行此之前索引您的customKey以提高速度

于 2016-03-19T07:44:40.600 回答
10

虽然@Stennie's 是一个有效的答案,但它不是唯一的方法。事实上,MongoDB 手册要求您在执行此操作时要非常谨慎。还有两个选择

  1. 让 MongoDB使用 Map Reduce为您做到这一点
  2. 您以编程方式执行效率较低。
于 2012-11-02T07:28:20.007 回答
8

这是一种稍微“手动”的方式:

本质上,首先,获取您感兴趣的所有唯一键的列表。

然后使用这些键中的每一个执行搜索,如果该搜索返回大于一,则删除。

    db.collection.distinct("key").forEach((num)=>{
      var i = 0;
      db.collection.find({key: num}).forEach((doc)=>{
        if (i)   db.collection.remove({key: num}, { justOne: true })
        i++
      })
    });
于 2017-08-23T12:51:15.710 回答
4

扩展费尔南多的答案,我发现它花费的时间太长,所以我修改了它。

var x = 0;
db.collection.distinct("field").forEach(fieldValue => {
  var i = 0;
  db.collection.find({ "field": fieldValue }).forEach(doc => {
    if (i) {
      db.collection.remove({ _id: doc._id });
    }
    i++;
    x += 1;
    if (x % 100 === 0) {
      print(x); // Every time we process 100 docs.
    }
  });
});

改进基本上是使用文档id进行删除,应该更快,并且还添加了操作的进度,您可以将迭代值更改为您想要的数量。

此外,在操作之前对字段进行索引也会有所帮助。

于 2020-03-29T15:37:42.703 回答
4

我有类似的要求,但我想保留最新的条目。以下查询适用于我的包含数百万条记录和重复项的集合。

/** Create a array to store all duplicate records ids*/
var duplicates = [];

/** Start Aggregation pipeline*/
db.collection.aggregate([
  {
    $match: { /** Add any filter here. Add index for filter keys*/
      filterKey: {
        $exists: false
      }
    }
  },
  {
    $sort: { /** Sort it in such a way that you want to retain first element*/
      createdAt: -1
    }
  },
  {
    $group: {
      _id: {
        key1: "$key1", key2:"$key2" /** These are the keys which define the duplicate. Here document with same value for key1 and key2 will be considered duplicate*/
      },
      dups: {
        $push: {
          _id: "$_id"
        }
      },
      count: {
        $sum: 1
      }
    }
  },
  {
    $match: {
      count: {
        "$gt": 1
      }
    }
  }
],
{
  allowDiskUse: true
}).forEach(function(doc){
  doc.dups.shift();
  doc.dups.forEach(function(dupId){
    duplicates.push(dupId._id);
  })
})

/** Delete the duplicates*/
var i,j,temparray,chunk = 100000;
for (i=0,j=duplicates.length; i<j; i+=chunk) {
    temparray = duplicates.slice(i,i+chunk);
    db.collection.bulkWrite([{deleteMany:{"filter":{"_id":{"$in":temparray}}}}])
}
于 2020-09-22T17:08:10.757 回答
2

如果你有足够的内存,你可以在 scala 中做这样的事情:

cole.find().groupBy(_.customField).filter(_._2.size>1).map(_._2.tail).flatten.map(_.id)
.foreach(x=>cole.remove({id $eq x})
于 2016-12-12T16:02:32.680 回答
1

pip install mongo_remove_duplicate_indexes

  1. 创建任何语言的脚本
  2. 遍历你的集合
  3. 创建新集合并在此集合中创建新索引,并将唯一设置为 true,请记住此索引必须与索引相同您希望从您的原始集合中删除具有相同名称的重复项,因为您有一个集合游戏,并且在此集合你有包含重复的字段流派,你希望删除,所以现在只需创建新集合 db.createCollection("cname") 创建新索引 db.cname.createIndex({'genre':1},unique:1)当您将仅首先插入具有相似类型的文档时,将被接受,其他将因重复密钥错误而被拒绝
  4. 现在只需将您收到的 json 格式值插入新集合并使用 ex pymongo.errors.DuplicateKeyError 的异常处理来处理异常

查看 mongo_remove_duplicate_indexes 的包源代码以便更好地理解

于 2016-11-02T18:50:32.123 回答