
在处理时间序列数据时,我们经常需要分析数据在不同时间点之间的变化量。例如,计算每小时的能耗增量、每日的用户活跃度变化等。MongoDB的聚合管道提供了一套强大的工具集,能够高效地完成这类复杂的分析任务。本教程将以一个具体的案例为例,详细讲解如何利用聚合管道计算特定字段在不同时间戳之间的差值。
假设我们有一个存储设备能耗数据的MongoDB集合,其文档结构如下:
[
{
_id: 1,
"timestamp": "2023-05-15T10:00:00Z",
"code": "abc",
"energy": 2333
},
{
_id: 2,
"timestamp": "2023-05-15T10:10:00Z",
"code": "abc",
"energy": 2340
},
// ... 其他 'abc' 类型数据
{
_id: 6,
"timestamp": "2023-05-15T11:00:00Z",
"code": "abc",
"energy": 2370
},
{
_id: 7,
"timestamp": "2023-05-15T10:00:00Z",
"code": "def",
"energy": 3455
},
{
_id: 8,
"timestamp": "2023-05-15T10:10:00Z",
"code": "def",
"energy": 3460
},
// ... 其他 'def' 类型数据
{
_id: 12,
"timestamp": "2023-05-15T11:00:00Z",
"code": "def",
"energy": 3500
}
]我们的目标是:对于每种code(例如"abc"和"def"),计算其在每个小时开始时的energy值与前一个小时开始时的energy值之间的差。例如,计算 2023-05-15T11:00:00Z 的 energy 值减去 2023-05-15T10:00:00Z 的 energy 值。
期望的输出格式如下:
[
{ "timestamp": "2023-05-15T11:00:00Z", "code": "abc", "energy": 37 },
{ "timestamp": "2023-05-15T11:00:00Z", "code": "def", "energy": 45 }
]我们将构建一个多阶段的聚合管道来解决这个问题。
完整的聚合管道如下:
db.collection.aggregate([
// 1. 初始排序:按代码和时间戳排序,确保后续分组和取首值正确
{
$sort: {
code: 1,
timestamp: 1
}
},
// 2. 分组并获取每小时的首个能量值:按代码和小时进行分组
{
$group: {
_id: {
code: "$code",
hour: {
$dateTrunc: {
date: "$timestamp",
unit: "hour"
}
}
},
energy: {
$first: "$energy"
}
}
},
// 3. 使用窗口函数计算前一个小时的能量值
{
$setWindowFields: {
partitionBy: "$_id.code", // 按代码分区
sortBy: {
"_id.hour": 1
}, // 在每个分区内按小时排序
output: {
prevEnergy: {
$push: "$energy",
window: {
documents: [
-1,
0
]
}
}
}
}
},
// 4. 过滤结果:移除没有前一个小时数据的记录
{
$match: {
"prevEnergy.1": {
$exists: true
}
}
},
// 5. 最终投影:计算差值并格式化输出
{
$project: {
_id: 0,
timestamp: "$_id.hour",
code: "$_id.code",
energy: {
$subtract: [
{
$last: "$prevEnergy"
},
{
$first: "$prevEnergy"
}
]
}
}
}
]){
$sort: {
code: 1,
timestamp: 1
}
}{
$group: {
_id: {
code: "$code",
hour: {
$dateTrunc: {
date: "$timestamp",
unit: "hour"
}
}
},
energy: {
$first: "$energy"
}
}
}经过此阶段,数据将变为:
[
{ "_id": { "code": "abc", "hour": ISODate("2023-05-15T10:00:00Z") }, "energy": 2333 },
{ "_id": { "code": "abc", "hour": ISODate("2023-05-15T11:00:00Z") }, "energy": 2370 },
{ "_id": { "code": "def", "hour": ISODate("2023-05-15T10:00:00Z") }, "energy": 3455 },
{ "_id": { "code": "def", "hour": ISODate("2023-05-15T11:00:00Z") }, "energy": 3500 }
]{
$setWindowFields: {
partitionBy: "$_id.code", // 按代码分区
sortBy: {
"_id.hour": 1
}, // 在每个分区内按小时排序
output: {
prevEnergy: {
$push: "$energy",
window: {
documents: [
-1,
0
]
}
}
}
}
}经过此阶段,数据将变为(部分示例):
[
{ "_id": { "code": "abc", "hour": ISODate("2023-05-15T10:00:00Z") }, "energy": 2333, "prevEnergy": [2333] }, // 第一个小时没有前一个值
{ "_id": { "code": "abc", "hour": ISODate("2023-05-15T11:00:00Z") }, "energy": 2370, "prevEnergy": [2333, 2370] },
{ "_id": { "code": "def", "hour": ISODate("2023-05-15T10:00:00Z") }, "energy": 3455, "prevEnergy": [3455] },
{ "_id": { "code": "def", "hour": ISODate("2023-05-15T11:00:00Z") }, "energy": 3500, "prevEnergy": [3455, 3500] }
]{
$match: {
"prevEnergy.1": {
$exists: true
}
}
}经过此阶段,数据将变为:
[
{ "_id": { "code": "abc", "hour": ISODate("2023-05-15T11:00:00Z") }, "energy": 2370, "prevEnergy": [2333, 2370] },
{ "_id": { "code": "def", "hour": ISODate("2023-05-15T11:00:00Z") }, "energy": 3500, "prevEnergy": [3455, 3500] }
]{
$project: {
_id: 0,
timestamp: "$_id.hour",
code: "$_id.code",
energy: {
$subtract: [
{
$last: "$prevEnergy"
},
{
$first: "$prevEnergy"
}
]
}
}
}最终输出将符合预期:
[
{ "timestamp": ISODate("2023-05-15T11:00:00Z"), "code": "abc", "energy": 37 },
{ "timestamp": ISODate("2023-05-15T11:00:00Z"), "code": "def", "energy": 45 }
]通过结合 $sort、$group、
以上就是MongoDB时间序列数据字段差值计算教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号