如何在Flutter中从Firebase实时数据库按条件筛选获取可用文档
解决方案
你需要的功能有两种实现方式,分别如下:
方案1:服务端查询(推荐)
直接在Firebase查询阶段就过滤出可用商品,不需要拉取全量数据,节省带宽和客户端性能开销。
修改DataStreamPublisher类的getMenuStream方法如下:
Stream<List<GetData>> getMenuStream() { // 直接在查询时添加过滤条件,只拉取Available为true的节点 final dataStream = database.child(curUser!.uid).child(dbChild) .orderByChild("Available") .equalTo(true) .onValue; final streamToPublish = dataStream.map((event) { // 兼容无数据的空场景 if (event.snapshot.value == null) return <GetData>[]; final dataMap = Map<String, dynamic>.from(event.snapshot.value); final dataList = dataMap.entries.map((e) { return GetData.fromRTDB(Map<String, dynamic>.from(e.value)); }).toList(); return dataList; }); return streamToPublish; }
注意:使用服务端查询需要在Firebase实时数据库的规则中为对应节点添加索引,避免查询性能下降,示例规则如下:
{ "rules": { "$uid": { "$dbChild": { ".indexOn": "Available" } } } }
方案2:客户端过滤(改动最小)
如果不想修改查询逻辑,可以在客户端处理数据时过滤不可用商品,修改getMenuStream方法如下:
Stream<List<GetData>> getMenuStream() { final dataStream = database.child(curUser!.uid).child(dbChild).onValue; final streamToPublish = dataStream.map((event) { if (event.snapshot.value == null) return <GetData>[]; final dataMap = Map<String, dynamic>.from(event.snapshot.value); final dataList = dataMap.entries // 先过滤出可用的节点 .where((e) => e.value["Available"] == true) // 再转换为GetData对象 .map((e) => GetData.fromRTDB(Map<String, dynamic>.from(e.value))) .toList(); return dataList; }); return streamToPublish; }
附加隐患修复
你现有代码中的avail列表初始化逻辑存在空安全问题:len是流返回数据后才赋值的,但avail是提前声明的late变量,首次加载时会触发空异常,建议修改初始化逻辑,把avail的初始化移到流返回数据之后:
if (snapshot.hasData) { data = snapshot.data; len = data!.length; // 在这里初始化avail,避免空异常 avail = List.generate(len!, (index) => false); // 原有后续逻辑保持不变 ... }
内容的提问来源于stack exchange,提问作者Ghulam Ahmad
相关产品推荐
相关产品推荐

