如何根据Mongodb中的键删除重复项?

use*_*659 50 optimization key duplicates mongodb

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

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

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

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

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

Ste*_*nie 76

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

db.things.ensureIndex({'source_references.key' : 1}, {unique : true, dropDups : true})
Run Code Online (Sandbox Code Playgroud)

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

重要说明:

  • dropDups选项已在MongoDB 3.0删除,因此需要采用不同的方法.例如,您可以按照以下建议使用聚合:即使在添加唯一键后,MongoDB也会复制文档.
  • 缺少该source_references.key字段的任何文档都将被视为具有值,因此缺少关键字段的后续文档将被删除.您可以添加sparse:true索引创建选项,以便索引仅适用于具有source_references.key字段的文档.

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

  • 在所有文档中都应该强制执行这样的解释 (3认同)

Kan*_*hal 52

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

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

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

  • 如果我需要搜索多个键而不是一个键,这将如何工作? (2认同)
  • 仅供参考,如果您想保留最新记录,请将 $gt 更改为 $lt db.myCollection.find({}, {myCustomKey:1}).sort({_id:1}).forEach(function(doc){ db .myCollection.remove({_id:{$lt:doc._id}, myCustomKey:doc.myCustomKey}); }) (2认同)

Ara*_*ram 8

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

  1. 让MongoDB 使用Map Reduce为您完成
  2. 你以编程方式做的效率较低.


小智 8

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

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

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

    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++
      })
    });
Run Code Online (Sandbox Code Playgroud)


May*_*tel 7

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

/** 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}}}}])
}
Run Code Online (Sandbox Code Playgroud)