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

Flutter循环迭代中正确更新Firebase批次号(batchNo)并实现分文档存储的方案

Flutter循环迭代中正确更新Firebase批次号(batchNo)并实现分文档存储的方案

我完全理解你现在的困扰——循环里批次号始终不更新,所有数据都挤到同一个Firebase文档里,试了好几种方法都没解决对吧?咱们先拆解问题根源,再一步步给出可行的解决方案。

问题核心原因

你遇到的问题本质是异步操作的同步问题:

  1. 最初的循环里调用loadAndUploadCsvData时没有加await,导致所有上传请求几乎同时发起,它们都会去Firebase查询当前最新的批次号,自然拿到的都是同一个值。
  2. 后来尝试维护本地_batchNo,但循环里的updateBatchNo也是异步函数,你没等它执行完成就进入下一次迭代,所以本地变量根本没来得及更新。

解决方案一:串行异步循环(最稳妥,适用于多场景)

这个方案的核心是让每一次上传任务都等上一次完成后再执行,确保Firebase里的批次号已经更新,下一次查询能拿到正确的值。

修改按钮点击事件为异步函数

把原来的循环改成异步循环,用await等待每一次上传完成:

onPressed: () async {
  // 遍历批次数据,每次等待上一个上传完成再进行下一个
  for (int index = 0; index < _batchDataList.length; index++) {
    final batchData = _batchDataList[index];
    await loadAndUploadCsvData(batchData.name, batchData.bytes);
    log("已完成第 ${index+1} 批次上传");
  }
},

优化loadAndUploadCsvData函数

把函数改成返回Future<void>,并且把批次文档的创建操作只执行一次(原来你在Excel行循环里重复执行set,这完全没必要):

Future<void> loadAndUploadCsvData(String name, Uint8List? bytes) async {
  String extension = name.split('.').last;
  // 先获取当前最新的批次号
  int batchNo = await getNextBatchNo();
  
  // 创建批次文档,只需要执行一次
  await _firestore
      .collection('availableBatches')
      .doc("batch$batchNo")
      .set({"batchNo": batchNo});

  if (extension == 'xls' || extension == "xlsx") {
    var excel = Excel.decodeBytes(bytes!);
    for (var table in excel.tables.keys) {
      for (var row in excel.tables[table]!.rows) {
        // 跳过表头行
        if (row[0]!.colIndex == 0 && row[0]!.rowIndex == 0) {
          continue;
        }
        // 创建联系人模型
        ContactModel currentContact = ContactModel(
          name: row[0]!.value,
          number: row[1]!.value,
          type: row[2]!.value,
          isCalled: false,
        );
        // 添加联系人到当前批次的子集合
        await _firestore
            .collection('availableBatches')
            .doc("batch$batchNo")
            .collection("batchCollection")
            .add(currentContact.toMap());
      }
    }
  }
}

解决方案二:预生成批次号(更高效,适用于单一操作场景)

如果你的上传过程中没有其他地方会修改Firebase的批次号,那可以只查询一次初始批次号,之后本地自增,减少Firebase查询次数:

修改按钮点击事件

onPressed: () async {
  // 先获取初始批次号
  int startBatchNo = await getNextBatchNo();
  // 遍历批次数据,用本地自增的批次号
  for (int index = 0; index < _batchDataList.length; index++) {
    final batchData = _batchDataList[index];
    int currentBatchNo = startBatchNo + index;
    await loadAndUploadCsvData(batchData.name, batchData.bytes, currentBatchNo);
    log("已完成第 ${index+1} 批次上传,批次号:$currentBatchNo");
  }
},

修改loadAndUploadCsvData函数

新增批次号参数,不用再查询Firebase:

Future<void> loadAndUploadCsvData(String name, Uint8List? bytes, int batchNo) async {
  String extension = name.split('.').last;
  
  // 创建批次文档
  await _firestore
      .collection('availableBatches')
      .doc("batch$batchNo")
      .set({"batchNo": batchNo});

  if (extension == 'xls' || extension == "xlsx") {
    var excel = Excel.decodeBytes(bytes!);
    for (var table in excel.tables.keys) {
      for (var row in excel.tables[table]!.rows) {
        if (row[0]!.colIndex == 0 && row[0]!.rowIndex == 0) {
          continue;
        }
        ContactModel currentContact = ContactModel(
          name: row[0]!.value,
          number: row[1]!.value,
          type: row[2]!.value,
          isCalled: false,
        );
        await _firestore
            .collection('availableBatches')
            .doc("batch$batchNo")
            .collection("batchCollection")
            .add(currentContact.toMap());
      }
    }
  }
}

关键注意点

  • 异步操作一定要用await等待完成,否则多个请求会“抢”同一个批次号。
  • 避免重复的Firebase写入操作(比如原来每行都执行set),既浪费资源又可能导致数据覆盖。
  • 如果有并发修改批次号的场景(比如多个用户同时上传),建议用Firebase的事务或者递增计数器来保证批次号的唯一性,不过你的场景应该是单一用户操作,上面的方案足够。

备注:内容来源于stack exchange,提问作者Joey Leo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 15:47:47