将项目推送到阵列并在同一请求中删除

时间:2017-07-08 01:02:50

标签: mongodb mongoose mongodb-query database

我有一个存储传感器数据的文档,其中传感器读数是存储在数组中的对象。例如:

{
  "readings": [
    {
      "timestamp": 1499475320,
      "temperature": 121
    },
    {
      "timestamp": 1499475326,
      "temperature": 93
    },
    {
      "timestamp": 1499475340,
      "temperature": 142
    }
  ]
}

我知道如何将项目推送/添加到"读数"阵列。但我需要的是当我向数组中添加一个项目时,我也希望"清理"该数组通过删除具有" timestamp"的项目值比截止时间早。

这可能在mongodb吗?

1 个答案:

答案 0 :(得分:1)

我看到你的方式,你基本上有两个选择,有不同的方法。

将数组限制为上限大小

这里的第一个选项是“不完全”你要求的,但它是实现和执行开销最少的选项。与您的问题的不同之处在于,我们不是“删除超过某个年龄”,而是简单地在数组中的条目总数上设置“限制/上限”。

这实际上是使用$slice$push修饰符完成的:

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”以及对整个数组大小保持“上限”。但是这里的一般想法是,第一个实现虽然与提出的不完全相同但实际上会做一个“足够好”的“内务管理”工作,对请求几乎没有额外的开销,或者实际上是实际的代码的实现

此外,虽然您可以随时“阅读数据” - > “修改” - > “保存”。这不是一个非常好的模式。为了获得最佳性能以及没有冲突的“一致性”,您应该使用原子操作进行修改,其方式与此处概述的相同。