将项目推送到数组并在同一请求中删除
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”以及保持整个数组大小的“上限”。但是这里的总体思路是,第一个实现,虽然与所要求的不完全相同,但实际上会做一个“足够好”的“家务管理”工作,几乎没有额外的请求开销,或者实际上是实际代码的实现.
此外,虽然您始终可以“读取数据”->“修改”->“保存”。这不是一个非常好的模式。为了获得最佳性能以及没有冲突的“一致性”,您应该使用原子操作以与此处概述的相同方式进行修改。
【讨论】:
以上是关于将项目推送到数组并在同一请求中删除的主要内容,如果未能解决你的问题,请参考以下文章