StreamBuilder 的 Firebase 查询出现并立即消失

Posted

技术标签:

【中文标题】StreamBuilder 的 Firebase 查询出现并立即消失【英文标题】:StreamBuilder's Firebase query appears and disappears instantly 【发布时间】:2021-10-09 23:50:57 【问题描述】:

我正在尝试查询一个 Stream,其中文档应该在 'unit' 数组中包含 'UretimKurulum' 和 '日期'应该等于或大于今天的日期。

在流式传输此查询时,我确实在短短几秒钟内得到了我想要的正确结果,然后它显示“无可用数据”。

下面是实际代码:

  final FirebaseFirestore _db = FirebaseFirestore.instance;

  final DateTime _now = DateTime.now();
  final String val = 'UretimKurulum';

  @override
  Widget build(BuildContext context) 
    return StreamBuilder<QuerySnapshot<Object>>(
      stream: _db.collection('Schedule').where('date', isGreaterThanOrEqualTo: _now).where('unit', arrayContains: val).snapshots(),
      builder: (context, snapshot) 
        if (snapshot.connectionState == ConnectionState.waiting) 
          return Center(child: LinearProgressIndicator());
         else 
          if (!snapshot.hasData) 
            return Center(child: Text('No Data Available'));
           else 
            return ListView.builder(
              itemCount: snapshot.data!.docs.length,
              itemBuilder: (context, index) 
                var docSnap = snapshot.data!.docs[index];
                return Text(docSnap.id);
              ,
            );
          
        
      ,
    );
  

如果我尝试删除:

if (!snapshot.hasData) 
            return Center(child: Text('No Data Available'));
          

我收到以下错误:

════════ Exception caught by widgets library ═══════════════════════════════════
The following TypeErrorImpl was thrown building StreamBuilder<QuerySnapshot<Object>>(dirty, state: _StreamBuilderBaseState<QuerySnapshot<Object>, AsyncSnapshot<QuerySnapshot<Object>>>#0508a):
Unexpected null value.

【问题讨论】:

这个问题是否与 Firestore 中的复合查询索引有关?调试控制台不显示添加索引的链接。 您可以尝试将|| snapshot.data == null 添加到if (!snapshot.hasData) 行。不知道会不会有什么效果,但值得一试。 @JaffaKetchup 不幸的是它没有效果 【参考方案1】:

第一件事

 //instead of DateTime 
 final DateTime _now = DateTime.now();
 //you should use Timestamp which is provided by Firebase Firestore
 final Timestamp timeNow = Timestamp.now();

第二件事

//instead of
where('unit', arrayContains: val)
//try this
where("unit", "arrayContains", val)

希望它应该可以工作,如果没有然后回复我,我会尝试找到其他解决方案。

【讨论】:

【参考方案2】:

当您没有在 Firestore 中创建必要的索引时,您会闪烁。您需要为涉及 >、>=、


  "collectionGroup": "Schedule",
  "queryScope": "COLLECTION",
  "fields": [
    
      "fieldPath": "unit",
      "arrayConfig": "CONTAINS"
    ,
    
      "fieldPath": "date",
      "order": "ASCENDING"
    
  ]
,

或者,如果您愿意,也可以从 Firestore 控制台手动执行。

【讨论】:

【参考方案3】:

确实,正如@blaneyneil 和我之前所说的那样,这是一个索引问题。

解决方案是从 Firebase 控制台创建一个复合集合索引,并将字段“todoUnit”索引为数组,将“日期”索引为升序。

【讨论】:

【参考方案4】:
    为什么要尝试删除检查数据?,如果数据为空或为空,一般标准的 UX 应该不显示任何数据。为了避免 null,您可以使用像 data ?? 'default-data'data == null ? 'no-data' : 'found-data' 这样的 elvis 运算符 适合日期时间的条件是使用DateTime.now().microsecondsSinceEpoch 而不是DateTime.now() 这个可选但更精确的数据有效 https://docs.w3cub.com/dart~2/dart-core/datetime/microsecondssinceepoch 你可以试试改变
// instead of
       if (!snapshot.hasData) 
            return Center(child: Text('No Data Available'));
           else 
            return ListView.builder(
              itemCount: snapshot.data!.docs.length,
              itemBuilder: (context, index) 
                var docSnap = snapshot.data!.docs[index];
                return Text(docSnap.id);
              ,
            );
          
// try this
       if (!snapshot.hasData) 
            return Center(child: Text('No Data Available'));
        
       return ListView.builder(
           itemCount: snapshot.data!.docs.length,
           itemBuilder: (context, index) 
              var docSnap = snapshot.data!.docs[index];
              return Text(docSnap.id);
           ,
        );
          

【讨论】:

以上是关于StreamBuilder 的 Firebase 查询出现并立即消失的主要内容,如果未能解决你的问题,请参考以下文章

使用 Firebase 收听 Stream 的结果与 StreamBuilder 不同

StreamBuilder 的 Firebase 查询出现并立即消失

使本地图像直接出现在聊天中,而不是等待网络图像(Streambuilder / Firebase)

Flutter/Firebase:如何减少对推送/弹出调用的 StreamBuilder 调用?

Flutter 在使用 StreamBuilder 从 firebase 加载数据之前显示红色错误屏幕,如何解决?

Flutter - 使用 StreamBuilder 从 firebase 获取数据后,如何使用 ScrollController 跳转到列表视图的底部?