时间序列集合是 MongoDB 5.0 版本新增的功能,它有效地存储了一段时期内的测量序列。时间序列数据是随着时间收集的任何类型的数据,并由一个或多个不变参数唯一标识, 这些不变参数通常又称为是数据源的元数据。
与普通集合相比,将时序数据存储在时序集合中提高了查询效率,减少了时序数据和次级索引(secondary index)的磁盘存储空间。
创建时间序列集合的命令:
db.createCollection( <name>, { timeseries: { // Added in MongoDB 5.0 timeField: <string>, // required for time series collections metaField: <string>, granularity: <string> }, expireAfterSeconds: <number>, } )
说明:
name 集合的名称
timeseries.timeField 必选参数,每个时间序列文档中包含日期的字段的名称。时间序列集合中的文档必须具有有效的 BSON 日期作为 timeField 的值。
timeseries.metaField 可选参数,每个时间序列文档中包含元数据的字段的名称。指定字段中的元数据应该是用于标记一系列唯一文档的数据。元数据应该很少(如果有的话)改变。指定字段的名称不可以是 _id 或与 timeseries.timeField 相同。元数据的字段可以是任何数据类型。
timeseries.granularity 可选参数,可选值为 "second", "minute", "hours", 默认值是 "seconds"。手动设置 granularity 参数以通过优化时间序列集合中的数据在内部存储的方式来提高性能。选择与连续传入测量之间的时间跨度最接近的 granularity 参数值来匹配。如果指定了 timeseries.metaField,则要考虑连续的传入的测量值和指定的 metaField 字段具有相同唯一值的时间跨度。如果测量值来自同一来源,则它们通常具有相同的唯一值。如果未指定 timeseries.metaField,请考虑插入集合中的所有测量值之间的时间跨度
expireAfterSeconds 可选参数 ,通过指定文档过期的秒数来启用时间序列集合中文档的自动删除
在向时间序列集合插入任何数据之前,我们需要手动将集合创建为时间序列类型的集合。你可以通过运行 db.createCollection 命令定义时间序列集合选项,或者从 @TimeSeries 注解中提供选项来创建时间序列集合。
使用 CollectionOptions 创建一个时间序列集合,例如:
template.createCollection("weather", CollectionOptions.timeSeries("timestamp"));
使用 MongoDB 驱动创建一个时间序列集合,例如:
template.execute(db -> { // 创建名为 weather 的时间序列 com.mongodb.client.model.CreateCollectionOptions options = new CreateCollectionOptions(); options.timeSeriesOptions(new TimeSeriesOptions("timestamp")); db.createCollection("weather", options); return "OK"; });
使用 @TimeSeries 注解创建一个时间序列集合,如下:
@TimeSeries(collection="weather", timeField = "timestamp") public class Measurement { String id; Instant timestamp; // ... } template.createCollection(Measurement.class);
(1)application.properties 配置文件
# Log logging.level.root=debug # MongoDB spring.data.mongodb.uri=mongodb://localhost:27017/test
(2)配置类
package com.hxstrive.springdata.mongodb.config; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.MongoDatabaseFactory; import org.springframework.data.mongodb.core.MongoTemplate; /** * 配置 MongoTemplate * @author hxstrive.com */ @Slf4j @Configuration public class AppConfig { @Bean public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory) { log.info("mongoTemplate({}, {})", mongoDatabaseFactory); return new MongoTemplate(mongoDatabaseFactory); } }
(3)实体定义
package com.hxstrive.springdata.mongodb.entity; import lombok.Builder; import lombok.Data; import lombok.ToString; import org.springframework.data.mongodb.core.mapping.TimeSeries; import java.time.Instant; @Data @ToString @Builder @TimeSeries(collection="weather", timeField = "timestamp", metaField = "name") public class Measurement { private String id; private Instant timestamp; private String name; }
(4)客户端代码
package com.hxstrive.springdata.mongodb; import com.hxstrive.springdata.mongodb.entity.Measurement; import com.mongodb.client.MongoCollection; import com.mongodb.client.model.CreateCollectionOptions; import com.mongodb.client.model.TimeSeriesOptions; import org.bson.Document; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.mongodb.core.CollectionOptions; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import java.time.Instant; import java.util.List; @SpringBootTest class TimeSeriesDemo { @Autowired private MongoTemplate mongoTemplate; @BeforeEach public void init() { mongoTemplate.dropCollection("weather"); } /** * 通过 CollectionOptions 创建时间序列集合 */ @Test public void createByCollectionOptions() { MongoCollection<Document> doc = mongoTemplate.createCollection("weather", CollectionOptions.timeSeries("timestamp")); System.out.println(doc); } /** * 通过 MongoDB 驱动创建时间序列集合 */ @Test public void createByDriver() { String str = mongoTemplate.execute(db -> { // 创建名为 weather 的时间序列 com.mongodb.client.model.CreateCollectionOptions options = new CreateCollectionOptions(); options.timeSeriesOptions(new TimeSeriesOptions("timestamp")); db.createCollection("weather", options); return "OK"; }); System.out.println(str); // 结果: // OK } /** * 通过注解创建时间序列集合 */ @Test public void createByAnnotation() { MongoCollection<Document> doc = mongoTemplate.createCollection(Measurement.class); System.out.println(doc); } /** * 创建集合、插入数据和查询数据 */ @Test public void simpleDemo() { // 创建集合 mongoTemplate.createCollection(Measurement.class); // 写入数据 mongoTemplate.insert(Measurement.builder().id("100").name("Bauer").timestamp(Instant.now()).build()); mongoTemplate.insert(Measurement.builder().id("200").name("Helen").timestamp(Instant.now()).build()); mongoTemplate.insert(Measurement.builder().id("300").name("Bill").timestamp(Instant.now()).build()); // 查询数据 List<Measurement> list = mongoTemplate.find( Query.query(Criteria.where("id").in("100", "200", "300")), Measurement.class); for(Measurement item : list) { System.out.println(item); } // 结果: // Measurement(id=100, timestamp=2023-05-23T02:21:45.688Z, name=Bauer) // Measurement(id=200, timestamp=2023-05-23T02:21:45.852Z, name=Helen) // Measurement(id=300, timestamp=2023-05-23T02:21:45.868Z, name=Bill) } }