最近在工作上遇到需要清理鸡汤文中重复的数据,网上搜了一下,有不少方案,有用程序去重的,有用唯一索引来控制的,感觉都不是很方便,后来发现用下面这个非常方便;
db.Passages.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.Passages.remove({_id: {$in: it.dups}});
});
下面来解析:
- 使用aggregate聚合查询重复数据
- $group中是查询条件,根据content、endTime、startTime字段来聚合相同的数据;
- $count用来统计重复出现的次数, $match来过滤没有重复的数据;
- $addToSet将聚合的数据id放入到dups数组中方便后面使用;
- 查询结果使用forEach进行迭代id来删除数据
- shift()作用是剔除队列中第一条id,避免删掉所有的数据;
PS:注意函数的大小写,mongoDB是严格区分大小写的!!!
今天发版本执行脚本的时候发现在mongo2.4x的版本下面执行报错:
MongoDB shell version: 2.4.9
connecting to: 192.168.xxx.xxx:27017/xxx
Tue Apr 3 18:41:26.268 TypeError: Object [object Object] has no method 'forEach' at xxx.js:11
failed to load: xxx.js
先开始以为是2.4x版本如果没有查到重复数据造成forEach报错,加上try、catch手动捕获异常避免脚本执行失败,后来检查数据发现有重复数据的也依然进异常了,这下就懵逼了,难道2.4x版本aggregat返回的数据跟3.x版本的还不一样?
var list = db.Passages.aggregate([
{
$group:{_id:{content:'$content',endTime:'$endTime',startTime:'$startTime'},count:{$sum:1},dups:{$addToSet:'$_id'}}
},
{
$match:{count:{$gt:1}}
}
]);
print([JSON.stringify(list));
最后把查出的数据打印出来,发现返回的都是一个json对象不是数组,2.4x版本的数据是放在reslut
字段下的,而3.x是放在·_batch·字段下(至于为什么可以直接forEach有待研究),当时心中一万只xxx奔腾而过,抱怨归抱怨bug还是要改的,当然就只能先判断一下版本罗。
经过反复修改测试,下面是最终修改结果。
var list = db.Passages.aggregate([
{
$group:{_id:{content:'$content',endTime:'$endTime',startTime:'$startTime'},count:{$sum:1},dups:{$addToSet:'$_id'}}
},
{
$match:{count:{$gt:1}}
}
]);
if(list._batch!=undefined){
print('v3.4....')
list.forEach(function(it){
it.dups.shift();
db.Passages.remove({_id: {$in: it.dups}});
});
}else{
print('v.2.4....')
list.result.forEach(function(it){
it.dups.shift();
db.Passages.remove({_id: {$in: it.dups}});
});
}