Firebase查询指定条件捐赠请求数据失败:求解决方案
解决Firestore查询无结果的问题
核心问题分析
- 查询条件完全写反:你需要查询
userEmail不等于当前用户邮箱的请求,但代码中错误使用了.where("userEmail", isEqualTo: userEmailID),这只会返回当前用户自己的请求,和需求完全相悖。 - 仅获取单个文档:当前代码只取查询结果的第一个文档,会丢失其他符合条件的请求数据。
- 缺少复合索引:Firestore同时使用多个
where条件和orderBy时,必须创建对应的复合索引,否则查询会失败或无结果。
修正后的完整代码
class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { final controller = Get.put(UserController()); bool donationRequestsLoading = true; // 改为List存储所有符合条件的请求 List<Map<String, dynamic>> donationRequests = []; Future<void> fetchDonationRequests() async { try { final userEmailID = controller.user.value.email; final userBlood = controller.user.value.bloodGroup; print('blood group: $userBlood'); // 空值校验,避免邮箱/血型为空导致查询异常 if (userEmailID == null || userBlood == null) { print("用户邮箱或血型为空,无法执行查询"); return; } QuerySnapshot querySnapshot = await FirebaseFirestore.instance .collection("Requests") .where("status", isEqualTo: "Pending") .where("bloodGroup", isEqualTo: userBlood) // 修正为"不等于当前用户邮箱"的条件 .where("userEmail", isNotEqualTo: userEmailID) .orderBy(FieldPath.documentId, descending: true) .get(); // 处理所有符合条件的文档 if (querySnapshot.docs.isNotEmpty) { donationRequests = querySnapshot.docs.map((doc) { final data = doc.data() as Map<String, dynamic>; // 额外存储文档ID,方便后续操作(如更新状态) data['docId'] = doc.id; return data; }).toList(); } else { donationRequests = []; } } catch (e) { print("获取捐赠请求失败: $e"); // 针对性提示常见错误 if (e.toString().contains("requires an index")) { print("请根据控制台提示的链接创建复合索引"); } else if (e.toString().contains("Missing or insufficient permissions")) { print("请检查Firestore安全规则是否允许读取Requests集合"); } } finally { setState(() { donationRequestsLoading = false; }); } } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { fetchDonationRequests(); }); } @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( child: Column( children: [ const EPrimaryHeaderContainer( child: Column( children: [ EHomeAppBar(), SizedBox(height: ESizes.spaceBtwInputFields), BloodGroupandNextDonation(), SizedBox(height: ESizes.spaceBtwSections), ], ), ), const RequestToBloodBank(), const SizedBox(height: 28), // 功能按钮区域 const Padding( padding: EdgeInsets.symmetric(horizontal: ESizes.defaultSpace), child: Column( children: [ Row( children: [ PostBloodRequest(), SizedBox(width: 12), BloodBanks(), SizedBox(width: 12), DonateBlood(), ], ), SizedBox(height: ESizes.spaceBtwInputFields), ], ), ), // 捐赠请求列表区域 ESectionHeading( title: 'Donation Requests', showActionButton: true, onPressed: () { Get.to(() => const DonationRequestsList()); }, ), const SizedBox(height: 1), donationRequestsLoading ? const Padding( padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), child: EShimmerEffect( width: double.infinity, height: 110, radius: 16, ), ) : donationRequests.isEmpty ? const Center( child: Text( "无捐赠请求", style: TextStyle(fontSize: 16, color: Colors.grey), ), ) // 改为横向列表展示多个请求 : SizedBox( height: 110, child: ListView.builder( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 20), itemCount: donationRequests.length, itemBuilder: (context, index) { return DonationRequests(donationMap: donationRequests[index]); }, ), ), const SizedBox(height: 10), ], ), ), ); } }
额外注意事项
- 复合索引创建:运行代码后如果控制台提示需要创建索引,复制提示中的链接到浏览器,按照引导完成索引创建即可。
- 安全规则配置:确保Firestore安全规则允许读取
Requests集合,示例规则如下(可根据实际需求调整):
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /Requests/{request} { allow read: if request.auth != null; // 仅允许登录用户读取 allow write: if request.auth != null; } } }
内容的提问来源于stack exchange,提问作者Emon
相关产品推荐
相关产品推荐

