9

我的代码

我有一个带有两个集合的 MongoDB,Items并且Calculations.

Items
  value:  Number
  date:   Date
Calculations
  calculation:  Number
  start_date:   Date
  end_date:     Date

A是基于数据库中所有日期在的开始日期和结束日期之间的值Calculation的存储计算。ItemItemsCalculation

Mongo 更改流

我认为创建/更新的一个好方法Calculations是在集合上创建一个 Mongo Change Stream,Items它侦听对集合的更改,Items然后重新计算相关的Calculations.

问题是,根据Mongo Change Event docs,当一个文档被删除时,该fullDocument字段被省略,这将阻止我访问已删除Item的日期,这将通知Calculations应该更新哪个。

问题

有没有办法访问fullDocument由于文档删除而触发的 Mongo 更改事件?

4

2 回答 2

5

不,我不相信有办法。来自https://docs.mongodb.com/manual/changeStreams/#event-notification

更改流仅通知已持久保存到副本集中大多数数据承载成员的数据更改。

当文档被删除并且删除在副本集中的大多数节点上持续存在时,该文档已不再存在于副本集中。因此,变更流不能返回不再存在的东西。

您的问题的解决方案是MongoDB 4.0 中的事务。也就是说,您可以在单个原子操作中调整Calculations和删除对应的。Items

于 2019-07-08T23:20:01.590 回答
0

fullDocument删除文档时不返回。

但是有一个解决方法。

在您删除文档之前,设置一个提示字段。(显然使用与您当前属性不冲突的名称。)

await myCollection.updateOne({_id:theId}, {_deleting: true})
await myCollection.deleteOne({_id:theId})

这将触发change流中的最后一个事件,并提示文档将被删除。然后在你的流观察器中,你简单地检查这个值。

stream.on('change', event => {
  if (!event.fullDocument) {
    // The document was deleted
  }
  else if (event.fullDocument._deleting) {
    // The document is going to be deleted
  }
  else {
   // Document created or updated
  }

})

我的 oplog 没有足够快地更新,并且更新正在查找已删除的文档,因此我需要添加一个小延迟以使其正常工作。

myCollection.updateOne({_id:theId}, {_deleting: true})
setTimeout( ()=> {
  myCollection.deleteOne({_id:theId})
}, 100)

如果文档最初不存在,则不会更新或删除,因此不会触发任何内容。

使用 TTL 索引

使这项工作的另一种方法是添加一个 ttl 索引,然后将该字段设置为当前时间。这将首先触发更新,然后自动删除文档。

myCollection.setIndex({_deleting:1}, {expireAfterSeconds:0})
myCollection.updateOne({_id:theId}, {$set:{_deleting:new Date()}})

这种方法的问题在于 mongo 仅在文档​​中所述的 60 秒或更长时间的特定时间间隔内修剪 TTL 文档,因此我更喜欢使用第一种方法。

于 2022-02-04T19:04:51.283 回答