我有一个存储传感器数据的文档,其中传感器读数是存储在数组中的对象。例如:
{
"readings": [
{
"timestamp": 1499475320,
"temperature": 121
},
{
"timestamp": 1499475326,
"temperature": 93
},
{
"timestamp": 1499475340,
"temperature": 142
}
]
}
我知道如何将项目推送/添加到"读数"阵列。但我需要的是当我向数组中添加一个项目时,我也希望"清理"该数组通过删除具有" timestamp"的项目值比截止时间早。
这可能在mongodb吗?
答案 0 :(得分:1)
我看到你的方式,你基本上有两个选择,有不同的方法。
这里的第一个选项是“不完全”你要求的,但它是实现和执行开销最少的选项。与您的问题的不同之处在于,我们不是“删除超过某个年龄”,而是简单地在数组中的条目总数上设置“限制/上限”。
Model.update(
{ "_id": docId },
{ "$push": {
"readings": {
"$each": [{ "timestamp": 1499478496679, "temperature": 100 }],
"$slice": -10
}
}
)
在这种情况下,-10
参数将数组限制为仅包含数组末尾的“最后十个”条目,因为我们正在使用$push
“追加”。如果您想要将“最新”作为第一个条目,那么您将使用$position
进行修改,而是将“正”值提供给$slice
,这意味着“前十”。相反。
所以它与你要求的不一样,但它是实用的,因为阵列没有“无限增长”,你可以在每次更新时简单地“限制”它们,并且“最旧的”项目将被删除一次在最大长度。这意味着整个文档实际上从未超出设定的大小,这对MongoDB来说是一件非常好的事情。
实际上完全按照您的要求执行的下一个案例使用“批量操作”在“单个”请求中向服务器发出“两个”更新操作。它之所以是“两个”,是因为有一条规则是你不能在单一的更新操作中将“不同的更新操作符”“分配到同一路径”。
因此,您想要的实际上涉及$push
和$pull
操作,并且在“相同的阵列路径”上我们需要将这些操作作为“单独”操作发出。这是批量API可以提供帮助的地方:
Model.collection.bulkWrite([
{ "updateOne": {
"filter": { "_id": docId },
"update": {
"$pull": {
"readings": { "timestamp": { "$lt": cutOff } }
}
}
}},
{ "updateOne": {
"filter": { "_id": docId },
"update": {
"$push": { "timestamp": 1499478496679, "temperature": 100 }
}
}}
])
这使用了您通过.collection
从模型访问的底层驱动程序中的.bulkWrite()
方法,如图所示。这实际上会在回调或Promise中返回BulkWriteOpResult
,其中包含有关“批处理”中执行的实际操作的信息。在这种情况下,它将是“匹配”和“修改”的数字,它们将适合于实际执行的操作。
因此,如果$pull
实际上没有“删除”任何内容,因为时间戳值实际上比给定约束更新,那么修改后的计数将仅反映$push
操作。但是大部分时间这都不需要你关注,相反,你只是接受操作完成而没有错误,并根据你的实际要求做了一些事情。
因此,“两者”的一般情况是,它实际上都是在一个请求和一个响应中完成的。差异在于“引擎盖下”与您的请求匹配的第二种方法实际上每次请求都执行“两次”操作,因此需要更长的时间。
实际上没有理由你不能“结合”“两者”的逻辑,并删除过去的“cutoFF”以及对整个数组大小保持“上限”。但是这里的一般想法是,第一个实现虽然与提出的不完全相同但实际上会做一个“足够好”的“内务管理”工作,对请求几乎没有额外的开销,或者实际上是实际的代码的实现
此外,虽然您可以随时“阅读数据” - > “修改” - > “保存”。这不是一个非常好的模式。为了获得最佳性能以及没有冲突的“一致性”,您应该使用原子操作进行修改,其方式与此处概述的相同。