我的问题是,交易只允许delete
,get
,set
和update
文件。
对于2人游戏,我需要创建游戏并加入游戏。这个想法如下:
这意味着,在没有对手的情况下搜索游戏并在事务中运行更新的查询。我怎么能这样做?
问题:
如果游戏在此期间(查询和更新之间)发生了变化并且已经更新了怎么办?我目前可能会覆盖其他一些在此期间加入游戏的玩家...我该如何解决这个问题呢?
代码
这是我到目前为止所做的:
// get a game without opponent
var gameQueryRef = db.collection('games')
.where('state', '==', '1')
.limit(1);
return gameQueryRef.get()
.then(querySnapshot => {
var gameRef = null;
if (querySnapshot.docs.length === 0) {
return null;
} else {
return querySnapshot.docs[0].ref;
}
})
.then(gameRef => {
log("GameRequest", gameRequestId, "gameRef = " + gameRef);
if (gameRef === null)
{
var newGameRef = db.collection("games").doc();
var game = {
state: 1,
creationDate: Date.now(),
finishDate: 0,
docPlayer1: docPlayer,
docPlayer2: null
};
return newGameRef.set(game);
}
else
{
// update game => THIS IS NOT SAVE!
// what if the game did change in the meantime and was updated already????
// I possibly override some other player who has joined this game in the meantime...
return gameRef.update(state => 2, docPlayer2 => docPlayer);
}
})
// continue with game
编辑 - 解决方案
我发布了一个可能的解决方案,我将测试,如果有人对此有评论,我也对此感兴趣。
答案 0 :(得分:0)
可能的解决方案
文档ID可以手动定义,并且必须在一个集合中是唯一的,因此我们可以在另一个集合中创建相同的文档。
所以我将创建一个我称之为GameLocks
的集合。
有了这个想法,我认为以下确实有效:
Game
的文档=>遗憾的是,在交易之外,所以我需要在交易中重新检查游戏的状态,以确保查询和交易之间没有任何变化transaction
:
GameLocks
文档是否存在(通过transaction.get
)与Game
文档=>具有相同ID如果是真的,我知道其他人已经尝试加入这个游戏,我可以处理这个,所以我在这里停止这个交易(要么我搜索另一个游戏,要么我只是开始一个没有对手的新游戏,等待其他人加入这个游戏)GameLock
文档,所以我创建了一个=>我只是将Game
的ID用于锁定transaction.get
)=>重要的是,因为我们在执行查询时没有处于事务中! =>结束交易,如果其他人已加入此游戏transaction.update
)GameLock
文档(通过transaction.delete
)通过在事务中运行锁定文档的create
和delete
操作并检查Game
以及它们之间的所有操作,我可以肯定没有其他人可以在两者之间操纵相同的Game
文档,这样就可以解决问题。