使用mongorestore合并MongoDB数据库未恢复全部文档的问题
解决MongoDB合并时mongorestore重复键导致部分文档未导入的问题
问题根源
虽然文档_id无冲突,但目标集合存在非_id的唯一索引,导致导入时触发重复键错误(E1000),mongorestore会跳过冲突文档,最终部分数据未成功导入。
解决步骤
1. 定位冲突的唯一索引
在目标数据库中查询集合的所有索引,找到标记为unique: true的非_id索引:
db.PoiAnalysis2.getIndexes()
输出结果中会包含类似如下的唯一索引项:
{ "v" : 2, "key" : { "some_business_field" : 1 }, "name" : "some_business_field_1", "unique" : true }
这里的some_business_field就是导致重复键冲突的字段。
2. 临时移除唯一约束(或跳过索引恢复)
有两种方式处理:
- 方式一:删除目标集合的冲突唯一索引
直接删除该唯一索引,避免导入时触发冲突:db.PoiAnalysis2.dropIndex("some_business_field_1") - 方式二:mongorestore时跳过索引恢复
如果不想提前修改目标集合,可在导入命令中添加--noIndexRestore参数,暂时不恢复索引:mongorestore --uri="mongodb://admin:password@localhost:27017/my_db?authSource=admin" --dir=my_db --authenticationDatabase=admin --numInsertionWorkersPerCollection=4 --gzip --noIndexRestore
3. 重新执行mongorestore导入
用修改后的命令重新导入,此时所有文档都会被写入目标集合(不会因唯一键冲突被跳过)。
4. 处理重复数据并重建索引(可选)
如果业务上需要保留该字段的唯一约束,导入完成后需先清理重复数据,再重建唯一索引:
- 清理重复数据(保留最新文档)
假设冲突字段为some_business_field,按_date_created保留最新的文档:db.PoiAnalysis2.aggregate([ { $group: { _id: "$some_business_field", docs: { $push: "$$ROOT" }, count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ]).forEach(function(group) { // 按创建时间倒序排序,保留第一个(最新),删除其余 group.docs.sort((a, b) => b._date_created - a._date_created); for (let i = 1; i < group.docs.length; i++) { db.PoiAnalysis2.deleteOne({ _id: group.docs[i]._id }); } }); - 重建唯一索引
清理完成后,重新创建唯一索引:db.PoiAnalysis2.createIndex({ some_business_field: 1 }, { unique: true })
5. 验证导入结果
执行原查询确认最新文档已导入:
db.getCollection("PoiAnalysis2").find({}).sort({_date_created: -1}).limit(1)
内容的提问来源于stack exchange,提问作者Tom McLean
相关产品推荐
相关产品推荐

