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

StreamBuilder's Firebase query appears and disappears instantly

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

在流式传输此查询时,我确实在几秒钟内得到了我想要的正确结果,然后显示 'No Data Available'。

下面是实际代码:

  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 中创建必要的索引时,您会眨眼。您需要为涉及 >、>=、<、<= 的任何查询创建索引。在你的情况下,你的 firestore.indexes.json:

中应该有类似下面的内容
{
  "collectionGroup": "Schedule",
  "queryScope": "COLLECTION",
  "fields": [
    {
      "fieldPath": "unit",
      "arrayConfig": "CONTAINS"
    },
    {
      "fieldPath": "date",
      "order": "ASCENDING"
    }
  ]
},

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

第一件事

 //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)

希望它能工作如果没有那么回复我我会尝试找到其他解决方案。

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

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

  1. 为什么要尝试删除校验数据?,如果数据为 null 或为空,则一般标准中的 UX 应该不显示任何数据。为避免空值,您可以使用 elvis 运算符,例如 data ?? 'default-data'data == null ? 'no-data' : 'found-data'
  2. 适合日期时间条件的是使用 DateTime.now().microsecondsSinceEpoch 而不是 DateTime.now() 这个可选但更精确的数据是有效的 https://docs.w3cub.com/dart~2/dart-core/datetime/microsecondssinceepoch
  3. 你可以尝试改变
// 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);
           },
        );