MongoDB默认将时间存储为UTC格式,并将所有本地时间表示形式转换为这种形式。必须对某个未修改的本地时间值进行操作或报告的应用程序可以将时区与UTC时间戳一起存储,并在其应用程序逻辑中计算原始本地时间。
在MongoDB Shell中,您可以存储当前日期和当前客户端与UTC的偏移量。
var now = new Date();
db.data.save( { date: now,
offset: now.getTimezoneOffset() } );
您可以通过应用保存的偏移量来重建原始本地时间:
var record = db.data.findOne();
var localNow = new Date( record.date.getTime() - ( record.offset * 60000 ) );
组织时间序列数据的一种常用方法是将数据分组到多个桶(bucket)中,其中每个桶(bucket)代表统一的时间单位,例如一天或一年。桶组织特定的数据组可以帮助:
考虑一个存储从传感器获得的温度数据的集合。传感器每分钟记录一次温度,并将数据存储在名为temperatures的集合中:
// temperatures collection
{
"_id": 1,
"sensor_id": 12345,
"timestamp": ISODate("2019-01-31T10:00:00.000Z"),
"temperature": 40
}
{
"_id": 2,
"sensor_id": 12345,
"timestamp": ISODate("2019-01-31T10:01:00.000Z"),
"temperature": 40
}
{
"_id": 3,
"sensor_id": 12345,
"timestamp": ISODate("2019-01-31T10:02:00.000Z"),
"temperature": 41
}
...
这种方法在数据和索引大小方面无法很好地扩展。例如,如果应用程序需要在sensor_id和 timestamp字段上建立索引,则需要对来自传感器的每个传入读数进行索引,用以提高性能。
您可以利用文档模型将数据存储到保存特定时间跨度的文档中。考虑以下更新的模式,该模式将每分钟获取的读数存储在一个小时的组中:
{
"_id": 1,
"sensor_id": 12345,
"start_date": ISODate("2019-01-31T10:00:00.000Z"),
"end_date": ISODate("2019-01-31T10:59:59.000Z"),
"measurements": [
{
"timestamp": ISODate("2019-01-31T10:00:00.000Z"),
"temperature": 40
},
{
"timestamp": ISODate("2019-01-31T10:01:00.000Z"),
"temperature": 40
},
...
{
"timestamp": ISODate("2019-01-31T10:42:00.000Z"),
"temperature": 42
}
],
"transaction_count": 42,
"sum_temperature": 1783
}
此更新的模式提高了可伸缩性,并反映了应用程序实际使用数据的方式。用户可能不会查询特定的温度读数。相反,用户可能会在一个小时或一天的时间内查询温度行为。桶模式通过将数据分组为统一的时间段来帮助简化这些查询。
以上实例文档包含两个计算字段:transaction_count和sum_temperature。如果应用程序经常需要检索给定时间的温度总和,则运行时计算总数可以帮助节省应用程序资源。这种计算模式方法无需在每次请求数据时都计算总和。
预先汇总sum_temperature和transaction_count的值可以进行进一步的计算,例如特定桶的平均温度(sum_temperature/ transaction_count)。用户更有可能向应用程序查询2:00和3:00 PM之间的平均温度,而不是查询2:03 PM的特定温度。通过桶和预先计算某些值,应用程序可以更轻松地提供该信息。
除时间序列数据外,桶模式对于物联网项目很有用,在该项目中,您拥有来自许多不同来源的多个数据集。将数据存储到组中(例如基于设备类型或系统)有助于更轻松地检索和解析数据。
进入MongoDB中文手册(4.2版本)目录