Firestore 集合查询作为颤动中的流

Posted

技术标签:

【中文标题】Firestore 集合查询作为颤动中的流【英文标题】:Firestore collection query as stream in flutter 【发布时间】:2020-04-11 01:44:12 【问题描述】:

我正在尝试从集合中查询一些文档,这个查询应该监听查询文档中所做的更改,所以我需要一个流。我正在关注(在 Dart/Flutter 中)

  Stream<List<MatchRequest>> _getNewMatches() 
    return Collection<MatchRequest>(path: 'requests')
        .ref
        .where('status', isNull: true)
        .where('users', arrayContains: ['$currentUid'])
        .orderBy('last_activity')
        .snapshots()
        .map((list) => list.documents.map(
            (doc) => Global.models[MatchRequest](doc.data) as MatchRequest));
  

(对象 Collection 在其构造函数中设置 ref 的路径,例如:ref = db.collection($path) 并且 map 对结果进行模型)

然后我使用带有stream 的StreamBuilder 调用上面的方法并builder 检查snapshot.hasData。但它一直在加载,snapshot.hasData 一直是假的。我在这里做错了什么?

编辑:

    我的 Firestore 安全规则包含:

    match /requests/requestId 
        allow read: if isLoggedIn();
        allow write: if isLoggedIn();
    
    

    删除每个 whereorderBy 时,它也找不到任何东西。并且请求集合中存在文档

    当尝试从请求集合中仅查询 1 个文档作为流时,他确实找到了结果

    是因为我应该向我的 Firestore 索引添加索引吗?但这并不能解决我的第一个问题,即即使没有whereorderBy,它也没有得到任何数据

【问题讨论】:

您的第一个问题可能是在您共享的代码上您没有听到任何内容。您有 snapshots() 但之后没有 listen() 。能够监听 Firestore 集合与索引无关,因此您无需担心。 【参考方案1】:

我写了一个简单的例子,它似乎就像你正在尝试做的但缺少 listen() 方法:

Firestore.instance.collection('collection')
  .where('field', isEqualTo: 'value')
  .orderBy('field')
  .snapshots()
  .listen((QuerySnapshot querySnapshot)
    querySnapshot.documents.forEach((document) => print(document));
  
);

这只是一个示例,说明如何从 Firestore 流中获取数据并将其用于 StreamBuilder:

class _MyHomePageState extends State<MyHomePage> 
  Stream dataList;

  @override
  void initState() 
    dataList = Firestore.instance.collection('collection')
      .where('field', isEqualTo: 'value')
      .orderBy('field')
      .snapshots();

    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: StreamBuilder(
          stream: dataList,
          builder: (context, asyncSnapshot) 
            if(asyncSnapshot.hasError)
              return Text('Error: $asyncSnapshot.error');

            switch (asyncSnapshot.connectionState) 
              case ConnectionState.none: return Text('No data');
              case ConnectionState.waiting: return Text('Awaiting...');
              case ConnectionState.active:
                return ListView(
                  children: asyncSnapshot.data.map((document) => Text(document['value'])),
                );
              break;
              case ConnectionState.done: return ListView(
                children: asyncSnapshot.data.map((document) => Text(document['value'])),
              );
              break;
            
            return null;
        ),
      ),
    );
  

 

【讨论】:

嗨!确实,在查找时,我发现了该 listen 方法。但我不是很明白。我所做的是将 snapshots() 结果作为 Stream 返回并在 snapshot.hasData 检查后进行映射:snapshot.data.documents .map((doc) =&gt; Global.models[MatchRequest](doc.data) as MatchRequest) .toList(); 现在我得到了数据,显然不需要索引。只需要删除我的数组包含中的“[]”括号。 我有点着急,所以我暂时保留这个,如果你对它的工作原理以及 listen() 的工作原理有一些解释,我很乐意有一些文件或你的解释。 啊,我的解决方案不听我看到的数据库更改... 我可以做到,但您不需要使用 StreamBuilder。您可以只使用一个变量来保存您的文档并将它们显示在您的视图上,并且只执行一个 setstate 以反映您的视图上的新更改。

以上是关于Firestore 集合查询作为颤动中的流的主要内容,如果未能解决你的问题,请参考以下文章

在颤动中使用 REST api 将列表数据发送到云 Firestore 时出错

颤动检查云Firestore集合中是不是存在用户ID

使用 StreamBuilder 获取 Firestore 文档,其中包含颤动中的地图列表

过滤 Streambuilder/listviewBuilder 颤动

颤动firebase检查集合是不是为空

如何在 Cloud Firestore 中使用文档 ID 执行集合组查询