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

Flutter药物提醒App中Firebase Firestore CRUD操作异常排查

Flutter + Firebase Cloud Firestore药物提醒App问题修复指南

存在的问题

  • 数据已在Firebase控制台显示,但App首页仍显示“Nothing to show. Add some medicines!”
  • Firestore文档ID未与用户认证生成的UID绑定
  • 药物数据错误存储在主集合Medicines中,而非用户专属的User-Medicines子集合

期望的Firestore结构

主集合Medicines下以用户UID为文档ID,每个文档对应User-Medicines子集合,存储该用户的所有药物数据。


当前CRUD操作代码

final FirebaseFirestore _firestore = FirebaseFirestore.instance; //initializing firebase firestore
final CollectionReference _mainCollection = _firestore.collection('Medicines'); //defining the main collection where all the database information will be stored

class Database {
  //this class contains all the crud functions
  static String? userID;

  //Create
  static Future<void> addMedicine({
    required String medicineName,
    required String dosageAmount,
    required int? frequency,
    required List<TimeOfDay?> doseTime,
    required String instructions,
    required String additionalInformation,
  }) async {
    DocumentReference documentReferencer = _mainCollection.doc(userID).collection('User-Medicines').doc();

    //below line converts the dosetime to firestore compatible format
    List<Map<String, int>> timesForFirestore = MedicineDataConverter.timeOfDayListToMapList(doseTime);

    Map<String, dynamic> medicine = {
      "Medicine Name": medicineName,
      "Dosage Amount": dosageAmount,
      "Frequency": frequency,
      "Date and Time": timesForFirestore,
      "Instructions": instructions,
      "Additional Information": additionalInformation,
    };

    await documentReferencer
        .set(medicine)
        .whenComplete(() => print('Medicine added to the database'))
        .catchError((e) => print(e));
  }

  //Read
  static Stream<QuerySnapshot> readMedicine() {
    return _mainCollection.doc(userID).collection('User-Medicines').snapshots();
    // CollectionReference medicineCollection = _mainCollection.doc(userID).collection('User-Medicines');

    // return medicineCollection.snapshots();
  }

  //Update
  static Future<void> updateMedicine({
    required String medicineName,
    required String dosageAmount,
    required int? frequency,
    required List<TimeOfDay?> doseTime,
    required String instructions,
    required String additionalInformation,
    required String docID,
  }) async {
    DocumentReference documentReferencer = _mainCollection.doc(userID).collection('Medicines').doc(docID);

    List<Map<String, int>> timesForFirestore = MedicineDataConverter.timeOfDayListToMapList(doseTime);

    Map<String, dynamic> medicine = {
      "Medicine Name": medicineName,
      "Dosage Amount": dosageAmount,
      "Frequency": frequency,
      "Date and Time": timesForFirestore,
      "Instructions": instructions,
      "Additional Information": additionalInformation,
    };

    await documentReferencer.update(medicine);
    // .whenComplete(() => print('Data updated'))
    // .catchError((e) => print(e));
  }

  //Delete
  static Future<void> deleteMedicine({
    required String docID,
  }) async {
    DocumentReference documentReferencer = _mainCollection.doc(userID).collection('Medicines').doc(docID);

    await documentReferencer.delete();
    // .whenComplete(() => print('Data deleted'))
    // .catchError((e) => print((e)));
  }
}

当前首页代码

body: StreamBuilder<QuerySnapshot>(
        stream: Database.readMedicine(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }

          if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
            return const Center(
              child: Text('Nothing to show. Add some medicines!'),
            );
          }

          return ListView.builder(
            itemCount: snapshot.data!.docs.length,
            itemBuilder: (context, index) {
              DocumentSnapshot medicine = snapshot.data!.docs[index];

              return Padding(
                padding: const EdgeInsets.all(15.0),
                child: ListTile(
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20)),
                  selectedColor: Colors.deepPurple,
                  iconColor: Colors.white,
                  textColor: Colors.white,
                  splashColor: Colors.purple,
                  title: Text(medicine['medicineName']),
                  subtitle: Text(medicine['dosageAmount']),
                  trailing: IconButton(
                    onPressed: () {
                      String docID = medicine.id;
                      deleteConfirmationDialogue(context, docID);
                    },
                    icon: const Icon(Icons.delete),
                  ),
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => MedicineDetailEditScreen(
                            medicineDocument: medicine),
                      ),
                    );
                  },
                ),
              );
            },
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.deepPurple,
        foregroundColor: Colors.white,
        splashColor: Colors.purple,
        onPressed: () {
          //go to addmedicine page
          Navigator.of(context).pushNamed(addMedicineRoute);
        },
        child: const Icon(Icons.add),
      ),

问题修复方案

1. 首页数据不显示修复

  • 字段名不匹配:代码中读取用的是medicineName/dosageAmount,但Firestore存储的是"Medicine Name"/"Dosage Amount",需统一字段命名规则(推荐驼峰式)。
  • userID未赋值:确保用户登录后,Database.userID被设置为当前用户UID,可在登录流程或App初始化时添加监听:
FirebaseAuth.instance.authStateChanges().listen((user) {
  if (user != null) {
    Database.userID = user.uid;
  } else {
    Database.userID = null;
    // 跳转登录页等逻辑
  }
});

2. 用户UID绑定修复

在用户完成认证后,必须将Database.userID赋值为当前用户UID,所有CRUD操作均基于该UID访问对应子集合,避免数据混乱。

3. 集合路径错误修复

updateMedicine和deleteMedicine方法中错误使用了collection('Medicines'),需改为collection('User-Medicines'),同时统一字段名:

修改后的updateMedicine方法

static Future<void> updateMedicine({
  required String medicineName,
  required String dosageAmount,
  required int? frequency,
  required List<TimeOfDay?> doseTime,
  required String instructions,
  required String additionalInformation,
  required String docID,
}) async {
  DocumentReference documentReferencer = _mainCollection.doc(userID).collection('User-Medicines').doc(docID);

  List<Map<String, int>> timesForFirestore = MedicineDataConverter.timeOfDayListToMapList(doseTime);

  Map<String, dynamic> medicine = {
    "medicineName": medicineName,
    "dosageAmount": dosageAmount,
    "frequency": frequency,
    "dateAndTime": timesForFirestore,
    "instructions": instructions,
    "additionalInformation": additionalInformation,
  };

  await documentReferencer.update(medicine)
      .whenComplete(() => print('Data updated'))
      .catchError((e) => print(e));
}

修改后的deleteMedicine方法

static Future<void> deleteMedicine({
  required String docID,
}) async {
  DocumentReference documentReferencer = _mainCollection.doc(userID).collection('User-Medicines').doc(docID);

  await documentReferencer.delete()
      .whenComplete(() => print('Data deleted'))
      .catchError((e) => print((e)));
}

修改后的addMedicine字段名

Map<String, dynamic> medicine = {
  "medicineName": medicineName,
  "dosageAmount": dosageAmount,
  "frequency": frequency,
  "dateAndTime": timesForFirestore,
  "instructions": instructions,
  "additionalInformation": additionalInformation,
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:44:54