gpt4 book ai didi

MongoDB 查找和修改。它真的是原子的吗?帮助编写一个封闭的更新解决方案

转载 作者:可可西里 更新时间:2023-11-01 09:44:12 30 4
gpt4 key购买 nike

我有 Event 文档,由嵌入的 Snapshots 组成。

如果满足以下条件,我想将 Snapshot A 添加到 Event 中:

  • 该事件在快照 A 的 5 分钟内开始
  • 事件的最新快照不早于快照 A 的一分钟。

否则....创建一个新的事件

这是我的 findAndUpdate 查询,它可能更有意义:

Event.findAndModify(
query: {
start_timestamp: { $gte: newSnapshot.timestamp - 5min },
last_snapshot_timestamp: { $gte: newSnapshot.timestamp - 1min }
},
update: {
snapshots[newSnapshot.timestamp]: newSnapshot,
$max: { last_snapshot_timestamp: newSnapshot.timestamp },
$min: { start_timestamp: newSnapshot.timestamp }
},
upsert: true,
$setOnInsert: { ALL OUR NEW EVENT FIELDS } }
)

编辑:不幸的是,我无法在 start_timestamp 上创建唯一索引。快照带有不同的时间戳,我想将它们分组到一个事件中。即快照 A 在 12:00:00 进入,快照 B 在 12:00:59 进入。它们应该在同一个事件中,但它们可以在不同时间写入数据库,因为写入它们的工作人员是同时进行的。假设另一个快照在 12:00:30 进来,它应该被写入与上面两个相同的事件。最后,应将 12:02:00 的快照写入新事件。

我的问题是......这能在并发环境中正常工作吗? findAndUpdate 是原子的吗?我是否可以创建两个事件,而我应该创建一个事件并将快照添加到其中?

编辑:因此不能保证上述方法不会创建两个事件,正如@chainh 友善指出的那样。

所以我尝试了一种新的基于锁定的方法 - 你认为这行得通吗?

var acquireLock = function() {
var query = { "locked": false}
var update = { $set: { "locked": true } }
return Lock.findAndModify({
query: query,
update: update,
upsert: true
})
};

var releaseLock = function() {
var query = { "locked": true }
var update = { $set: { "locked": false } }
return Lock.findAndModify({
query: query,
update: update
})
};

var insertSnapshot = function(newSnapshot, upsert) {
Event.findAndModify(
query: {
start_timestamp: { $gte: newSnapshot.timestamp - 5min },
last_snapshot_timestamp: { $gte: newSnapshot.timestamp - 1min }
},
update: {
snapshots[newSnapshot.timestamp]: newSnapshot,
$max: { last_snapshot_timestamp: newSnapshot.timestamp },
$min: { start_timestamp: newSnapshot.timestamp }
},
upsert: upsert,
$setOnInsert: { ALL OUR NEW EVENT FIELDS } }
)
};

var safelyInsertEvent = function(snapshot) {
return insertSnapshot(snapshot, false)
.then(function(modifyRes) {
if (!modifyRes.succeeded) {
return acquireLock()
}
})
.then(function(lockRes) {
if (lockRes.succeeded) {
return insertSnapshot(snapshot, true)
} else {
throw new AcquiringLockError("Didn't acquire lock. Try again")
}
})
.then(function() {
return releaseLock()
})
.catch(AcquiringLockError, function(err) {
return safelyInsertEvent(snapshot)
})
};

锁定文档将只包含一个字段(锁定)。基本上上面的代码试图找到一个现有的事件并更新它。如果它有效,很好,我们可以摆脱困境。如果我们没有更新,我们知道我们没有现有的事件来插入快照。所以我们然后以原子方式获取锁,如果成功,我们可以安全地插入一个新事件。如果获取该锁失败,我们只需再次尝试整个过程,希望到那时我们有一个现有事件可以将其插入。

最佳答案

findAndModify 可能会在并发环境下插入多个事件。除非您的事件文档包含具有唯一索引的字段,否则只有一个 findAndModify 成功插入新事件,而其他 findAndModify 将失败并重试向新事件添加快照.有关详细信息,请参阅此 jira 票证:https://jira.mongodb.org/browse/DOCS-861

关于MongoDB 查找和修改。它真的是原子的吗?帮助编写一个封闭的更新解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26355394/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com