Firestore多层测试数据存储优化及快速加载方案咨询
优化Firestore测试数据存储与加载性能
问题背景
当前场景为多测试、每测试包含多个问题、每个问题带多个选项,数据层级为「Test 1 > q1、q2、q3... > question: hello, answer: opt 2, opt 1: a, opt 2: b, opt 3: c, opt 4: d」。使用以下代码写入Firestore时加载延迟严重,需优化存储结构实现测试快速加载:
for (var i = 1; i < totalquestions + 1; i++) { await FirebaseFirestore.instance .collection("users") .doc(user!.uid) .collection('Test $no') .doc(i.toString()) .set( Map<String, dynamic>.from( Provider.of<Question>(context, listen: false) .question[i]!, ), ); await FirebaseFirestore.instance .collection("users") .doc(user.uid) .collection('Test $no') .doc(i.toString()) .update( { 'yourAns': Provider.of<Question>(context, listen: false) .answers[i]! .values .first }, ); }
优化方案
1. 合并写入操作,减少网络请求
原代码每个问题都执行set+update两次独立请求,循环N次就会产生2N次网络调用,这是延迟的核心原因。直接把yourAns字段整合到初始写入的Map里,一次完成数据提交:
for (var i = 1; i < totalquestions + 1; i++) { // 合并问题数据和用户答案 Map<String, dynamic> questionData = Map<String, dynamic>.from( Provider.of<Question>(context, listen: false).question[i]!, ); questionData['yourAns'] = Provider.of<Question>(context, listen: false) .answers[i]! .values .first; await FirebaseFirestore.instance .collection("users") .doc(user!.uid) .collection('Test $no') .doc(i.toString()) .set(questionData); }
2. 调整数据结构,减少文档数量
不要给每个问题单独创建文档,而是把整个测试的所有问题数据放到单个文档中。这样加载测试时只需要读取一次文档就能获取全部内容,大幅降低网络交互次数:
// 写入整个测试数据到单个文档 await FirebaseFirestore.instance .collection("users") .doc(user!.uid) .collection("tests") // 统一用tests集合管理所有测试 .doc('Test $no') .set({ 'questions': Provider.of<Question>(context, listen: false).question.values.toList(), 'userAnswers': Provider.of<Question>(context, listen: false).answers.map((key, val) => MapEntry(key, val.values.first)) });
读取时只需获取该文档,解析里面的questions数组和userAnswers对象即可,加载速度会显著提升。
3. 使用批量写入(Batched Writes)
如果必须保留“每个问题一个文档”的结构,改用Firestore的批量写入功能,把多个写入请求合并为一次提交,减少网络往返开销:
WriteBatch batch = FirebaseFirestore.instance.batch(); CollectionReference testCol = FirebaseFirestore.instance .collection("users") .doc(user!.uid) .collection('Test $no'); for (var i = 1; i < totalquestions + 1; i++) { DocumentReference docRef = testCol.doc(i.toString()); Map<String, dynamic> data = Map<String, dynamic>.from( Provider.of<Question>(context, listen: false).question[i]!, ); data['yourAns'] = Provider.of<Question>(context, listen: false) .answers[i]! .values .first; batch.set(docRef, data); } // 一次性提交所有操作 await batch.commit();
内容的提问来源于stack exchange,提问作者Sibusiso Mahlangu
相关产品推荐
相关产品推荐

