assert: command failed: {
"ok" : 0,
"errmsg" : "insert for $out failed: { connectionId: 65, err: \"E11000 duplicate key error collection: admin.tmp.agg_out.6 index: _id_ dup key: { : 1 }\", code: 11000, codeName: \"DuplicateKey\", n: 0, ok: 1.0 }",
"code" : 16996,
"codeName" : "Location16996"
} : aggregate failed
最近在做聚合(aggreate)处理时总是报以上的错误,现在分析可能导致其发生几个原因
1. 数据库中存在重复数据
当存在重复数据时,我们需要对重复的数据保留一条外删除其余的重复文档数据(document),我们可以根据数据量的大小来使用不同的方法对重复数据进行删除
1.1 当数据量较小时(具体不好把握,大约几万几十万条吧),我们可以这样处理(以下dbname为表名,fieldname为字段名):
var duplicates = [];
db.dbname.aggregate([
{ $group: {
_id: { fieldname: "$fieldname"}, // 根据一个或多个字段进行分组,字段相同的document为一组
dups: { "$addToSet": "$_id" }, //将字段相同的document的_id放在一个列表中
count: { "$sum": 1 } //统计相同document的个数
}},
{ $match: {
count: { "$gt": 1 } // 匹配大于1条的document
}}
])
.forEach(function(doc) {
doc.dups.shift(); // 对于重复的document,保留第一条,剩下的的删除
doc.dups.forEach( function(dupId){
duplicates.push(dupId); // 获取要删除的_id字段
}
)
})
// 如果你想查看删除的重复的document的_id字段,你可以使用下面这句话
printjson(duplicates);
// 一次删除重复的数据
db.dbname.remove({_id:{$in:duplicates}})
以上详细可以查看:
https://stackoverflow.com/questions/13190370/how-to-remove-duplicates-based-on-a-key-in-mongodb/13190994
1.2 当数据量很大时(几千万到几亿数据量),我们可以这样处理:
1.2.1 将数据以json格式导出(假设表名为data)
mongoexport -d 数据库名 -c data -o D:\data.json
1.2.2 删除data表
db.data.remove({})
或者
使用robomongo客户端的话可以直接右键+drop collection
1.2.3 重新建一个名为data的表并建立唯一索引
注意:在data中我们可以找一下哪一个字段必须是唯一的,比如我有一个关于论文信息的表,那它的doi就一定是唯一的,只要doi重复就说明两条数据一定是重复的,就必须删除那些重复的
db.data.ensureIndex({dbfield: 1},{unique: 1})//dbfield指的是那个唯一的字段
1.2.4 将json数据导入data中
mongoimport -d 数据库名 -c 数据表 --type json --file D:\data.json
在导入的过程中,我们发现重复记录被删除,这种方法速度虽然不大快,但确实真的好用,推荐!!!
2. 使用聚合(aggreate)时应该注意的导致数据重复的原因
db.all.aggregate([
{$lookup: {
from: 'data',
localField: 'doi',
foreignField: 'cited',
as: 'data_docs'}
},
{$unwind: '$data_docs'},
{$addFields: {year: '$data_docs.year'}},
{$addFields: {citing_doi: '$data_docs.citing'}},
{$project: {
// _id: false,
year: 1,
three_type: 1,
citing_doi: 1
}
},
{$out:"Question_1"}
],
{"allowDiskUse": true }
)
以上大家只需要关注一个点,那就是在使用unwind后一条记录document会变成多个记录document,但是它们的)_id是一样的,众所周知,_id为唯一字段,如果使用out导出来的话使用的还是原来的_id,那样就会报字段重复的错,怎样解决呢,我们可以在$project中添加一句:_id: false,如上图所示,这样使用out后就会自动生成新的_id,避免了重复!