报表需分层设计:高频固定报表用预聚合嵌入主文档,动态维度报表用多态+稀疏索引,原始明细单独分桶存储;预聚合只存高频、低频更新、高计算代价字段,避免冗余和文档膨胀。
直接说结论:报表场景不能靠“通用文档结构”一劳永逸,必须按具体报表的查询频率、字段组合、更新节奏来分层设计——高频固定报表用预聚合嵌入,动态维度报表用多态+稀疏索引,原始明细数据单独存。
该,但只放真正高频、低频更新、计算代价高的聚合结果。比如电商后台“用户昨日订单数+总金额”这种固定口径指标,直接存在 users 集合的 report_summary 字段里,用 $inc 原子更新。
user_reports 集合,用 user_id + report_type + date_range 作复合主键$lookup 或应用层关联用多态文档 + 稀疏索引,而不是搞一个万能 custom_fields 数组。MongoDB 允许同一集合内文档结构不同,这正是优势所在。
{"region":"华东","channel":"小程序"} 或 {"region":"华北","promotion_code":"SUMMER2026"},缺失字段不写,不填 null
db.sales.createIndex({region: 1, channel: 1}, {sparse: true}),避免为大量缺失字段建无效索引项custom_attributes: [{key:"xxx",value:"yyy"}] 这种键值对数组——查询无法走索引,聚合也得用 $unwind 拖慢性能单独建集合,按时间分桶,不和业务主文档混在一起。报表需要的是统计结果,不是实时查百万级明细。
events_20260706_14、events_20260706_15,用 TTL 索引自动过期({expireAfterSeconds: 2592000})user_id、event_type、timestamp、payload(必要上下文JSON),去掉所有冗余描述字段aggregate() 管道,别用 find() 拉全量——尤其避免在聚合里用 $lookup 关联大集合,先用 $facet 或分步预计算最容易被忽略的点是:报表需求变一次,文档结构就得跟着动一次。所谓“灵活”,不是靠一个 schema 支撑所有可能,而是靠快速迭代能力——用 MongoDB 的无模式特性,在 report_configs 集合里存每张报表的字段映射规则,再配合应用层动态生成聚合管道,这才是真正可落地的灵活性。