You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore如何更新数组特定元素?双人游戏场景问题

解决Firestore数组元素并发更新冲突的方案

针对你遇到的并发更新计时器数据被覆盖的问题,有两种实用的解决思路,根据你的需求选择即可:

方案一:重构文档结构(推荐)

核心是把players从数组改为用户ID为键的映射结构,这样可以精准更新单个玩家的time字段,完全避免并发覆盖问题。

修改后的文档结构

{
  "status": "string",
  "created_by": "string",
  "players": {
    "user_id_1": {
      "time": 123
    },
    "user_id_2": {
      "time": 456
    }
  }
}

对应代码实现

创建游戏会话

Future<String> createGameSession() async {
  final user = AuthProvider().getUser();
  final sessionRef = await _firestore.collection('game_sessions').add({
    'created_by': user.uid,
    'status': 'open',
    'players': {
      user.uid: {} // 初始可留空或设time为0
    },
  });
  gameSessionId = sessionRef.id;
  return sessionRef.id;
}

添加第二名玩家

Future<void> addPlayerGameSession() async {
  final user = AuthProvider().getUser();
  await _firestore.collection('game_sessions').doc(gameSessionId).update({
    'status': 'closed',
    'players.${user.uid}': {}
  });
}

更新玩家计时器数据

Future<void> updatePlayerTime(int time) async {
  final user = AuthProvider().getUser();
  await _firestore.collection('game_sessions').doc(gameSessionId).update({
    'players.${user.uid}.time': time
  });
}

这种方案从根源解决了并发问题,Firestore会仅修改指定路径的字段,不同玩家的更新操作完全独立,不会互相覆盖,且实现简单、性能高效。


方案二:使用Firestore事务(适合无法修改文档结构的场景)

如果不能调整现有结构,可以用Firestore事务确保更新的原子性:先读取文档最新状态,修改后再提交,若中途有其他修改,事务会自动重试,避免数据覆盖。

代码实现

Future<void> updatePlayerTimeWithTransaction(int time) async {
  final user = AuthProvider().getUser();
  await _firestore.runTransaction((transaction) async {
    final sessionDoc = await transaction.get(_firestore.collection('game_sessions').doc(gameSessionId));
    if (!sessionDoc.exists) {
      throw Exception("游戏会话不存在");
    }
    
    // 复制数组避免直接修改原数据
    List<dynamic> players = List.from(sessionDoc.data()!['players']);
    // 定位当前玩家的数组索引
    int userIndex = players.indexWhere((p) => p['id'] == user.uid);
    if (userIndex == -1) {
      throw Exception("玩家不在当前会话中");
    }
    
    // 更新计时器数据
    players[userIndex]['time'] = time;
    
    // 提交更新
    transaction.update(sessionDoc.reference, {'players': players});
  });
}

注意:事务会自动重试几次,若并发冲突频繁,可能需要额外添加自定义重试逻辑,但双人游戏场景下基本够用。


内容的提问来源于stack exchange,提问作者Dani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:15:17