时间序列集合必须用 createcollection() 显式创建,不能由 orm 自动建表;写入时 timefield 必须为 bson date 类型且非空,metafield 字段需存在且类型一致,粒度参数仅影响压缩不报错,且不支持 _id 自增、唯一索引和 text 索引。

必须用 CreateCollection() 显式创建,不能靠 ORM 自动建表;写入时字段名、类型、时间戳格式必须严格匹配定义。
创建时间序列集合必须用 CreateCollection() 命令
MongoDB 6.0 不支持在应用层(比如 Mongoid、Mongoose)通过模型定义自动创建时间序列集合。即使你写了 timeseries: { timeField: "timestamp" } 这类配置,驱动也不会触发底层 create 命令。
- 必须显式调用
db.CreateCollection()(Go 驱动)或db.createCollection()(mongosh) -
timeField字段名必须是字符串,且所有写入文档中该字段值必须为有效 BSONDate类型(不是字符串、数字或毫秒时间戳) - 如果指定了
metaField(如"sensor_id"),则每个文档都必须包含该字段,且值类型要一致(不能有时是字符串、有时是 ObjectId) - 不支持在已有普通集合上用
collMod升级为时间序列集合——只能新建
timeField 写入失败的常见原因
写入报错 WriteError: time series collection requires a valid date for time field 是最常遇到的问题,本质是时间字段没过校验。
- 传了字符串如
"2024-03-15T12:00:00Z":MongoDB 不自动解析,必须用new Date("2024-03-15T12:00:00Z")或驱动提供的日期构造函数(Go 中用time.Time) - 传了 Unix 秒数或毫秒数(如
1710504000):不行,必须是完整Date对象 -
timeField值为null、undefined或缺失字段:直接拒绝写入 - 使用了
ISODate()但时区处理出错(比如本地时区偏移未归一):建议统一用 UTC 时间写入
Go 驱动写入示例与关键参数检查
以下 Go 片段能跑通的前提是:集合已用 CreateCollection() 创建好,且 timeField 确为 "timestamp":
type Measurement struct {
Temperature int `bson:"temperature"`
Timestamp time.Time `bson:"timestamp"` // 必须是 time.Time,不能是 int64 或 string
SensorID string `bson:"sensor_id"`
}
doc := Measurement{
Temperature: 23,
Timestamp: time.Now().UTC(), // 关键:必须是 UTC time.Time
SensorID: "s001",
}
_, err := collection.InsertOne(context.TODO(), doc)
- struct tag 中的字段名(如
bson:"timestamp")必须和timeField定义完全一致,大小写敏感 - 如果用了
metaField: "sensor_id",则InsertOne的文档里sensor_id字段不能缺,也不能为nil - 避免用
bson.M手动构造文档——容易漏掉类型转换,推荐用 struct + 正确字段类型
粒度(granularity)影响写入行为但不报错
granularity: "minutes" 这类设置不会导致写入失败,但它决定了数据如何被压缩进“桶”(bucket),进而影响查询效率和磁盘占用。
- 选
"seconds"适合高频采集(如每秒 10 次传感器读数),但桶更碎、索引略大 - 选
"hours"适合低频数据(如每日汇总),单桶容纳更多点,但按分钟查会变慢 - 6.3+ 支持
bucketMaxSpanSeconds替代granularity,但 6.0 只认granularity字符串值 - 这个参数只在创建时生效,后续无法用
collMod修改——想换粒度只能导出重建集合
最容易被忽略的是:时间序列集合不支持 _id 自增、不支持唯一索引、不支持 text 索引——这些限制会在你加索引或做聚合时突然暴露,而不是在写入那一刻。











