我正在使用Expressjs,Socket.io和Mongoose制作多人游戏。玩家加入游戏,并在有足够的玩家玩游戏时开始游戏。我在游戏启动的同时警告游戏中的所有玩家,所以我遇到了将游戏状态改为“玩”并初始化角色的并发问题。有时候角色会被分配两次,这会让游戏变得混乱。
我尝试按照推荐的here和here添加一个nonce,但我无法让它工作,我真的不明白它。 MongoDB是否将其视为具有特殊属性的特殊值?或者是nonce取决于MongoDB的一些现有属性?
以下是游戏模型的相关部分:
GameSchema = mongoose.Schema
nonce:
type: mongoose.Schema.Types.ObjectId
required: true
default: mongoose.Types.ObjectId
name:
type: String
required: true
unique: true
state:
type: String
enum: ["setup", "unstarted", "playing", "assassinating", "good_won", "bad_won", "discontinued"]
default: "setup"
required: true
characters: [String]
players: [{ type: mongoose.Schema.Types.ObjectId, ref: "Player" }]
GameSchema.statics.findByIdAndStart = (id, done) ->
Game = this
Game.findById id, (err, game) ->
return done err, game if err or game.state is "playing"
changes =
state: "playing"
nonce: mongoose.Types.ObjectId()
Game.update { id: id, nonce: game.nonce }, changes, (err) ->
return done err if err
Game.findById(id).populate("players").exec (err, game) ->
return done err if err
characterSelection = new CharacterSelection game.characters
async.eachSeries game.players, ((player, next) ->
player.character = characterSelection.assignCharacter()
player.save next
), (err) -> done err, game
如何防止同时编辑模型?
答案 0 :(得分:2)
将模型的属性命名为#34; nonce"没有什么特别之处。它只是一个术语/惯例含义"只使用一次"我们要求它在每次生成时都是唯一的。
您将nonce定义为MongoDB中的ObjectId,以便每次生成它时都应获得唯一值。
这项工作的关键是当你调用update()时,你使用doc的现有nonce值,这样你的更新可以确保在你发出findById()和发出findById()之间没有其他玩家或用户更新了doc。调用更新方法。如果更新成功,您的文档将获得您在更改对象中添加的新生成的nonce值。
查看您的代码我认为它看起来是正确的,除非您没有处理更新没有更改任何记录的情况,只有错误情况。更新回调(in Mongoose 3.8.x)采用第二个参数numberAffected,您可以使用该参数确定是否存在受影响的文档。
Game.update { id: id, nonce: game.nonce }, changes, (err, numberAffected) ->
return done err if err
return done "Conflict!" if !numberAffected
您需要决定如何处理冲突案例,在this example中,代码会在错误输出之前多次重试该调用。