将项目推送到数组并在同一请求中删除

Posted

技术标签:

【中文标题】将项目推送到数组并在同一请求中删除【英文标题】:Push Item to Array and Delete in the Same Request 【发布时间】:2017-12-12 09:17:57 【问题描述】:

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


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

我知道如何将项目推送/添加到“读数”数组。但是我需要的是,当我向数组中添加一个项目时,我还想通过删除“时间戳”值早于截止时间的项目来“清理”数组。

在 mongodb 中可以吗?

【问题讨论】:

您认为提供的答案中是否有某些内容无法解决您的问题?如果是这样,请对答案发表评论,以澄清究竟需要解决哪些尚未解决的问题。如果它确实回答了您提出的问题,请注意Accept your Answers您提出的问题 @NeilLunn 我正在尝试获取您提供的 bulkWrite 答案。一旦我得到它的工作,我会接受。谢谢。 您在这里度过了很多时光。这不是一个不常见的过程,基本上在您提出的问题上,提供的代码“按原样”工作,无需更改。因此,为了“让它工作”,您实际上没有什么可做的,而只是简单地实现所解释的内容。如果回答确实解决了所提出的问题,或者您认为没有解释为什么不“在给出的答案上的 cmets”中不接受答案,则不接受答案是不礼貌的,因此作者能够回复并解决您的疑虑。请不要问问题,然后放弃它们。人们付出了努力。 【参考方案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 
    
  
])

这使用来自底层驱动程序的.bulkWrite() 方法,您可以通过.collection 从模型访问该方法,如图所示。这实际上将在回调或 Promise 中返回一个BulkWriteOpResult,其中包含有关“批处理”中执行的实际操作的信息。在这种情况下,它将是适合实际执行的操作的“匹配”和“修改”数字。

因此,如果 $pull 实际上没有“删除”任何内容,因为时间戳值实际上比给定的约束更新,那么修改后的计数将仅反映 $push 操作。但大多数情况下,这与您无关,您只需接受操作完成且没有错误,并按照您实际要求的内容进行操作。


结束

所以“两者”的一般情况是它实际上都是在一个请求和一个响应中完成的。不同之处在于,与您的请求相匹配的第二种方法“在后台”实际上会为每个请求执行“两次”操作,因此需要更长的时间。

实际上没有理由不能“组合”“两者”的逻辑,并删除“cutoFF”以及保持整个数组大小的“上限”。但是这里的总体思路是,第一个实现,虽然与所要求的不完全相同,但实际上会做一个“足够好”的“家务管理”工作,几乎没有额外的请求开销,或者实际上是实际代码的实现.

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

【讨论】:

以上是关于将项目推送到数组并在同一请求中删除的主要内容,如果未能解决你的问题,请参考以下文章

关闭md-dialog后,将项目推送到数组

Javascript/jQuery - 将项目推送到数组并从数组中删除

Laravel 中的数组推送

React JS将项目推送到数组以获取列表

如何推送对象值而不是数组中对象的引用

如何将数组推送到 laravel 中的现有会话