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
相关产品推荐
相关产品推荐

