在MongoDB上踩过的坑(Capped Collection)

设计光年求职的职位存储时,选择了MongoDB的Capped Collection。出发点是:

  1. 阿里云最低配的机器只有512MB的内存,职位超4万后搜索的响应极速下降,有必要缩小数据的规模。
  2. 由于招聘职位是时效性很强的信息,定期删除时间较久远的记录是用户能够容忍的。
  3. 虽然TTL索引也能实现记录的自动删除,但之前的项目经验告诉我它的自动删除并不同时释放硬盘空间。

Capped Collection只能新建,MongoDB并不提供普通Collection到Capped Collection的转换指令。

1
db.createCollection("test", { capped: true })

如果想把普通Collection转变成Capped Collection,可通过新建Capped Collection->拷贝旧Collection的数据->重命名覆盖旧Collection实现,拷贝数据的指令稍微复杂了点:

1
db.<collection_name>.find().forEach(function(doc){ db.<collection_name>.insert(doc); });

Capped Collection对性能的提升是显著的,即便除_id外不允许创建索引,搜索也普遍能在5s内返回。(光年求职并不是一个依赖搜索的应用)。
但是,转换没多久就出了个这么个事:由于被抓取页面的变化,导致好几条数据不完整,我通过Python脚本删除发现没有成功,于是到命令行下执行删除,返回:can’t remove from a capped collection
这时查看MongoDB的文档才发现这么一条规则:

You cannot delete documents from a capped collection. To remove all records from a capped collection, use the ‘emptycapped’ command. To remove the collection entirely, use the drop() method.

意思是Capped Collection的文档不能单独被删除。灵机一动,不能删,那加个状态码通过服务器程序过滤行不行?

1
db.<collection_name>.update({"_id": 11 }, { "$set": new_job })

结果也执行失败,继续看MongoDB的文档,又发现一条规则:

You can update documents in a collection after inserting them. However, these updates cannot cause the documents to grow. If the update operation causes the document to grow beyond their original size, the update operation will fail.

意思就是文档的更新必须在不增加文档占用空间的前提下才能生效,比如减少字段或减少值的长度。