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

Firestore动态创建用户专属日记集合并访问的代码修正求助

修正后的Firebase Firestore日记服务代码

问题分析

你修改后的代码主要存在三个核心问题:

  • 异步方法调用未使用await,导致拿到的是Future<String>而非实际邮箱字符串,强制类型转换引发错误
  • 邮箱包含@、.等Firestore集合名不允许的特殊字符,直接用作集合名会触发异常
  • 未做空安全处理,当用户文档不存在或缺少email字段时会崩溃

完整修正代码

import 'package:cloud_firestore/cloud_firestore.dart';

class DatabaseService {
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  // 用户相关操作
  Future<void> addUserData(UserModel userData) async {
    await _db.collection("Users").doc(userData.uid).set(userData.toMap());
  }

  Future<List<UserModel>> retrieveUserData() async {
    QuerySnapshot<Map<String, dynamic>> snapshot =
        await _db.collection("Users").get();
    return snapshot.docs
        .map((docSnapshot) => UserModel.fromDocumentSnapshot(docSnapshot))
        .toList();
  }

  Future<String?> retrieveUserName(UserModel user) async {
    DocumentSnapshot<Map<String, dynamic>> snapshot =
        await _db.collection("Users").doc(user.uid).get();
    return snapshot.data()?["displayName"]; // 空安全处理,避免崩溃
  }

  Future<String?> retrieveUserEmail(UserModel user) async {
    DocumentSnapshot<Map<String, dynamic>> snapshot =
        await _db.collection("Users").doc(user.uid).get();
    return snapshot.data()?["email"]; // 空安全处理
  }

  // 处理邮箱特殊字符,转换为Firestore允许的集合名
  String _sanitizeEmailForCollection(String email) {
    return email.replaceAll("@", "%40").replaceAll(".", "%2E");
  }

  // 日记条目操作(修正后)
  Future<void> addEntryData(UserModel user, EntryModel entryData) async {
    // 异步获取邮箱并处理特殊字符
    final String? userEmail = await retrieveUserEmail(user);
    if (userEmail == null) {
      throw Exception("用户邮箱不存在");
    }
    final String sanitizedEmail = _sanitizeEmailForCollection(userEmail);
    // 使用Firestore自动生成文档ID,避免手动指定ID重复
    await _db.collection(sanitizedEmail).doc().set(entryData.toMap());
  }

  Future<List<EntryModel>> retrieveEntryData(UserModel user) async {
    final String? userEmail = await retrieveUserEmail(user);
    if (userEmail == null) {
      throw Exception("用户邮箱不存在");
    }
    final String sanitizedEmail = _sanitizeEmailForCollection(userEmail);
    QuerySnapshot<Map<String, dynamic>> snapshot =
        await _db.collection(sanitizedEmail).orderBy("date").get();
    return snapshot.docs
        .map((docSnapshot) => EntryModel.fromDocumentSnapshot(docSnapshot))
        .toList();
  }
}

// 参考:UserModel和EntryModel的标准定义
class UserModel {
  final String uid;
  final String? displayName;
  final String? email;

  UserModel({required this.uid, this.displayName, this.email});

  Map<String, dynamic> toMap() {
    return {
      "uid": uid,
      "displayName": displayName,
      "email": email,
    };
  }

  factory UserModel.fromDocumentSnapshot(DocumentSnapshot<Map<String, dynamic>> doc) {
    return UserModel(
      uid: doc["uid"],
      displayName: doc["displayName"],
      email: doc["email"],
    );
  }
}

class EntryModel {
  final String? title;
  final String content;
  final DateTime date;

  EntryModel({this.title, required this.content, required this.date});

  Map<String, dynamic> toMap() {
    return {
      "title": title,
      "content": content,
      "date": Timestamp.fromDate(date),
    };
  }

  factory EntryModel.fromDocumentSnapshot(DocumentSnapshot<Map<String, dynamic>> doc) {
    return EntryModel(
      title: doc["title"],
      content: doc["content"],
      date: (doc["date"] as Timestamp).toDate(),
    );
  }
}

关键修改说明

  1. 异步操作修正:所有调用retrieveUserEmail的地方添加await,确保拿到实际邮箱字符串,而非Future对象。
  2. 邮箱特殊字符处理:新增_sanitizeEmailForCollection方法,将邮箱中的@、.转换为URL编码,符合Firestore集合名规则。
  3. 空安全与错误处理:将返回类型改为String?,添加空判断避免空指针崩溃;若邮箱不存在则抛出异常,方便上层捕获处理。
  4. 文档ID优化:添加日记条目时使用Firestore自动生成的文档ID(.doc()不带参数),避免手动指定ID可能出现的重复问题。

额外建议

如果不需要展示用户邮箱,更推荐使用用户UID作为集合名——UID是Firebase生成的唯一标识符,无特殊字符,无需额外处理,只需把retrieveUserEmail替换为直接使用user.uid即可,代码会更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:05:08