MongoDB 不支持基于文档结构的读写分离,读写分离仅发生在节点层级(primary/secondary),由驱动根据 readPreference 决定路由,不解析查询条件;真实需求通常为按业务类型分流、集合级读偏好或强一致性读,需应用层显式控制。

readPreference 发往整个节点,无法指定“只把 users 集合里 status=active 的文档发到 secondary”。
如果你看到类似描述,通常是误用术语,真实需求往往属于以下三类之一,需对应解决:
为什么不能按文档结构做读写分离
MongoDB 副本集的读写路由发生在连接层和查询分发层,驱动(如 PyMongo、MongoDB Java Driver)收到一个 find() 或 aggregate() 请求后,只看当前操作的 readPreference 和集群拓扑,不解析查询条件里的字段、值或路径。无论你查 { name: "alice" } 还是 { "profile.city": "shanghai" },只要设了 readPreference=secondary,整个查询就发给某个 secondary 节点执行;没设,就默认走 primary。
你真正想做的可能是这三件事之一
常见真实意图及对应做法:
-
按业务类型分流读请求:比如报表类查询走 secondary,用户实时查询走 primary。这不是靠文档结构判断,而是代码里显式控制——
collection.find(...).read_preference(ReadPreference.SECONDARY)或对特定 Repository 方法加注解(Spring Data MongoDB 中可用@ReadPreference) -
让某些集合默认走从节点:比如日志集合
logs全部读 secondary,用户集合users默认读 primary。需在应用层封装:为logs创建专用 client 实例,初始化时传入readPreference=secondary;不要试图在同一个 client 上靠 collection 名自动切换 -
写后立刻读到最新数据(“读己写”):这和读写分离相反,需要强制走 primary + 合理
writeConcern。例如插入后立即查,必须用readPreference=primary,且写时设w=majority,再配合readConcern=majority(MongoDB ≥3.2)才能保证一致性
容易踩的坑:误以为加了 $expr 或 $lookup 就能触发结构感知路由
即便查询用了复杂管道(如 $lookup 关联 orders 和 users),或带 $expr、$where,驱动依然只认 readPreference 设置,不会拆解 pipeline 去判断哪段该走哪个节点。更危险的是:readPreference=secondary 下执行含写操作的聚合(如 $out 或 $merge)会直接报错——secondary 不允许写,连语法校验都不通过。
另外,maxStalenessSeconds 参数常被忽略:设成 3600(1小时)意味着可能读到一小时前的数据,尤其跨地域部署时,延迟监控只看 rs.status().members[n].optimeDate 和主节点差距,不看这个参数实际生效值。

















