MongoDB遍历日期数组逐天删除大集合数据循环执行异常求助
逐天删除大集合文档的问题定位与可运行修正方案
两个直接导致功能失效的代码bug
- remove 方法参数传错,完全不符合MongoDB语法规则
MongoDB shell 里remove()的固定参数结构是remove(过滤条件, 执行配置),第一个参数才是用来匹配文档的查询规则,第二个参数是写关注、是否单条删除这类执行配置,根本不支持把第二个过滤条件拆成第二个参数传入。你之前把{'URL':/https:\/\/abc.com/}当第二个参数传进去,完全没有参与文档匹配,MongoDB收到不认识的配置项,轻则直接忽略,重则触发报错断连。
这也是为啥你执行后只输出到2018-04-06-day就停、返回nRemoved:0的直接原因:查询条件只剩time_bucket: 当天值,没有URL的匹配规则,遇到不合法的参数配置直接抛错退出循环,根本没跑完整个日期数组。 - 正则表达式写法有疏漏
你写的URL匹配正则没给域名里的点加转义,abc.com里的.在正则里是匹配任意字符的意思,会把abcXcom这类不符合预期的字符串也匹配上,容易误删。
可直接落地的修正代码
把所有过滤条件合并到第一个参数里,用语义更清晰的deleteMany()替换容易混淆参数的remove():
days = ['2018-04-01-day','2018-04-02-day','2018-04-03-day','2018-04-04-day','2018-04-05-day','2018-04-06-day','2018-04-07-day','2018-04-08-day','2018-04-09-day','2018-04-10-day','2018-04-11-day','2018-04-12-day','2018-04-13-day','2018-04-14-day','2018-04-15-day','2018-04-16-day','2018-04-17-day','2018-04-18-day','2018-04-19-day','2018-04-20-day','2018-04-21-day','2018-04-22-day','2018-04-23-day','2018-04-24-day','2018-04-25-day','2018-04-26-day','2018-04-27-day','2018-04-28-day','2018-04-29-day','2018-04-30-day'] var day; for(day of days) { print(`正在处理日期: ${day}`) const delRes = db.<你的集合名>.deleteMany({ // 两个匹配规则并列写在同一个过滤对象里 'time_bucket': day, // 修正正则的转义 'URL': /^https:\/\/abc\.com/ }) print(`本次已删除 ${delRes.deletedCount} 条文档`) }
解决大集合删除超时的核心优化
你之前按月份删超时,本质是删除查询没有命中合适索引,MongoDB需要全表扫描才能匹配到要删的文档,数据量大了自然卡在超时阈值里。
- 直接给删除的两个匹配字段建复合索引,后台运行不锁表:
建完索引后,删除操作可以直接通过索引定位到要删的文档,不需要扫全表,哪怕单天有几万条数据也能几秒内完成,不会触发超时。db.<你的集合名>.createIndex( {time_bucket:1, URL:1}, {background: true} ) - 如果单天符合条件的文档量特别大(超过10万条),可以在循环里加批量限制,每批删3000-5000条,删完当天的所有数据再进入下一个日期的处理,避免单条delete操作跑太久触发连接超时。
- 批量离线删除的时候,可以给delete操作加低等级写关注,只要主节点写入成功就返回,不用等从节点同步,能进一步降低操作耗时:
db.<你的集合名>.deleteMany( {匹配规则}, {writeConcern: {w: 1}} )
内容的提问来源于stack exchange,提问作者Patthebug
相关产品推荐
相关产品推荐

