如何直接在MongoDB维护索引,避免Rails应用覆盖彼此索引?
当然可以直接在MongoDB层面创建/删除索引,这正是解决你这种多Rails应用共享同一张MongoDB集合、但索引需求不同场景的最佳方案。先帮你理清楚问题根源,再一步步给出解决办法:
问题根源
Mongoid的bundle exec rake db:mongoid:remove_indexes命令会删除所有当前应用模型定义中未声明的索引——这就是为什么两个应用互相跑这个命令时,会把对方需要的索引删掉(比如应用1跑这个命令会删掉应用2的internal_comment索引,反之亦然)。
具体解决步骤
1. 停止使用remove_indexes命令
两个应用都不要再执行这个命令,只保留bundle exec rake db:mongoid:create_indexes。这个命令只会创建当前应用模型里定义的索引(如果不存在的话),不会删除任何已有的索引——哪怕是其他应用或者手动创建的。
2. 手动创建跨应用的专属索引
直接通过MongoDB Shell(或者MongoDB Compass等可视化工具)创建两个应用各自需要但对方没定义的索引:
// 创建应用1需要的status_id索引 db.orders.createIndex({ status_id: 1 }, { background: true }) // 创建应用2需要的internal_comment索引 db.orders.createIndex({ internal_comment: 1 }, { background: true })
这两个索引创建后会一直保留,不管哪个应用执行create_indexes,都不会被删除——因为create_indexes只负责补全自己模型里的索引,不会清理额外的索引。
针对你场景中疑问的解释
应用1插入订单时的索引问题
插入操作会自动维护所有已存在的索引,包括你手动创建的internal_comment索引,完全不会有问题。之前你遇到的异常应该是因为该索引还没被创建,手动创建后就会正常工作。
应用2查询internal_comment: { $ne: nil }的性能
只要internal_comment的索引存在,这个查询就会走索引,不会出现慢查询的情况。MongoDB对$ne: nil的查询支持索引优化,能快速定位到包含该字段(且不为null)的文档。
应用2更新订单对索引的影响
MongoDB的更新操作会自动维护所有相关索引:
- 更新
internal_comment字段时,会同步更新internal_comment的索引; status_id字段没被修改,对应的索引不会有任何变化;
不管是Mongoid创建的还是手动创建的索引,都会被正确维护,无需担心。
进阶优化建议
如果你们长期需要这种多应用共享集合的模式,可以在每个应用的Mongoid配置里禁用自动索引清理(防止意外删除索引):
# config/initializers/mongoid.rb Mongoid.configure do |config| # 禁用自动删除未在模型中定义的索引 config.auto_index = false end
内容的提问来源于stack exchange,提问作者JohnSmith1976

