小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
前言
众所周知,我们常常会用MongoDB存储大量数据。然而,有时候我们忘记在建立集合的时候给某些字段设置unique属性,导致数据库中会存在大量重复的数据,这时候如何删除这些数据就成了一个令人脑壳疼的问题。在数据量较小的情况下,可以直接写一个python脚本,通过导出已有数据并插入到已建立unique索引的集合中解决问题。但是,but,如果数据量较大的话,使用脚本来解决要耗费非常大量的时间,这种时候就需要想想其他办法了
几种方法
方法一:使用python脚本处理
from pymongo import MongoClient
# 打开集合
client = MongoClient(address, port)
db = client.db_name
collection = db.collection_name
patents = [] # 存储已遍历过的unique字段
count = 0
for item in collection.find():
if item['key_is_unique'] not in patents: # 判断当前文档是否在之前已经遍历过
patents.append(item['key_is_unique']) # 该文档设置成已遍历
else:
collection.delete_one(item) # 删除重复文档
方法二:在mongo命令行使用命令直接处理
db.Collection.aggregate([
{
$group:{_id:{content:'$content',endTime:'$endTime',startTime:'$startTime'},count:{$sum:1},dups:{$addToSet:'$_id'}}
},
{
$match:{count:{$gt:1}}
}
]).forEach(function(it){
it.dups.shift();
db.Collection.remove({_id: {$in: it.dups}});
});
对命令的一些说明
- 使用aggregate聚合查询重复数据
- $group中是查询条件,根据content、endTime、startTime字段来聚合相同的数据;
- $count用来统计重复出现的次数, $match来过滤没有重复的数据;
- $addToSet将聚合的数据id放入到dups数组中方便后面使用;
- 查询结果使用forEach进行迭代id来删除数据
- shift()作用是剔除队列中第一条id,避免删掉所有的数据;
方法三:直接在原集合建立索引,在让MongoDB在建立索引的过程中删除重复数据
db.Collection.ensureIndex({your_unique_key:1}, {unique: true, dropDups: true})
上述命令的dropDups参数告诉MongoDB,如果遇上了unique冲突的数据,就直接删除冲突的数据
方法四:通过MongoDB的原生支持,先导出数据为bson文件,再将bson文件数据导入到已建立索引的新集合中
mongodump -d db_name -c collection_name -o /tmp
db.new_collection_name.ensureIndex({要建立的索引}, {unique : true, dropDups : true})
mongorestore -d db_name -c new_collection_name /tmp/db_name/collection_name .bson
结语
上述提供了四周删除重复数据的方法,每种方法各有自己的优缺点,大家可以根据自己的需要进行选择。