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

Flutter下Firestore子集合数据快速获取优化方案咨询

优化Firestore子集合数据获取方案

你的代码慢的核心原因是串行发起每个日期文档的Reimbursement查询,当月如果有30天,就等于30次网络请求的耗时累加,自然会拖到8-10秒。以下两种优化方案可以解决这个问题:


方案1:并行执行所有日期查询(无需修改数据结构)

用Future.wait替代串行的await,让所有日期的Reimbursement查询同时发起,总耗时等于最慢的单个请求时间,而非所有请求时间之和。

修改后的代码:

getAllReimbursement(month, year) async {
  allReimbursement.clear();
  List<ReimbursementModel> reimbursementList = [];

  // 获取当月所有日期文档
  final monthRef = await FirebaseFirestore.instance
      .collection("Company")
      .doc(ConstantValue.companyId)
      .collection("Year")
      .doc(year)
      .collection(month)
      .get();
  final dateDocs = monthRef.docs;

  // 生成所有日期的Reimbursement查询Future列表
  final queryFutures = dateDocs.map((dateDoc) {
    return dateDoc.reference
        .collection("Reimbursement")
        .where("sendTo", isEqualTo: ConstantValue.userEmail)
        .get();
  }).toList();

  // 并行等待所有查询完成
  final queryResults = await Future.wait(queryFutures);

  // 合并所有查询结果
  for (final result in queryResults) {
    reimbursementList.addAll(
      result.docs.map((doc) => ReimbursementModel.fromJson(doc.data())).toList(),
    );
  }

  allReimbursement = reimbursementList;
  return reimbursementList;
}

这个方案能把耗时从8-10秒压缩到1-2秒左右,见效最快,不需要调整现有数据结构。


方案2:扁平化数据结构(极致性能优化)

Firestore的深层子集合查询天生需要遍历父文档,最优解是把报销数据扁平化存储,避免嵌套层级。可以单独创建一个Reimbursements集合,每个文档包含查询所需的所有维度字段:

新数据结构

Reimbursements(集合)
  -> reimbursement_id(文档)
     - companyId: "xxx"       // 公司ID
     - year: "2024"           // 年份
     - month: "05"            // 月份
     - date: "15"             // 日期
     - sendTo: "user@example.com"  // 收件人邮箱
     - ...其他报销相关字段

优化后的查询代码

getAllReimbursement(month, year) async {
  allReimbursement.clear();
  
  // 一次查询直接获取所有符合条件的报销数据
  final querySnapshot = await FirebaseFirestore.instance
      .collection("Reimbursements")
      .where("companyId", isEqualTo: ConstantValue.companyId)
      .where("year", isEqualTo: year)
      .where("month", isEqualTo: month)
      .where("sendTo", isEqualTo: ConstantValue.userEmail)
      .get();

  final reimbursementList = querySnapshot.docs
      .map((doc) => ReimbursementModel.fromJson(doc.data()))
      .toList();
  
  allReimbursement = reimbursementList;
  return reimbursementList;
}

额外优化

给companyId、year、month、sendTo创建复合索引(Firestore会在你第一次执行这个查询时提示你创建索引的链接,直接点击生成即可),能让查询速度再提升一个档次,总耗时通常在几百毫秒以内,完全满足页面加载前获取数据的需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:45:23