【问题标题】:Flutter & Firebase: Return list of collectionsFlutter & Firebase:返回集合列表
【发布时间】:2020-11-10 11:44:00
【问题描述】:

找不到任何关于此的信息,因为这里已经使用“listCollections()”或“getCollections()”的答案甚至不是有效的方法。

我有一个这样的数据库设置:

Layout:  Collection -> Document -> Collection -> Documents
  Example Data:
  Stores  -> UID  -> StoreName1 -> 
                     StoreName2 -> 
                     StoreName3 -> 

鉴于我知道 Stores 和 UID,我应该能够轻松地返回上面的所有商店名称。必须有一行代码可以给我结果:StoreName1、StoreName2 和 StoreName3。

这是我所拥有的:

CollectionReference documents = (await Firestore.instance.collection('Stores').document(widget.currentUserUID).    <---- now what?   There is no getCollections, there is no listCollections.   How can I return this information?

编辑

因此,在与下面的 Peter 讨论过这个问题后,我尝试通过一种调整后的方法来工作,但它看起来非常混乱。有没有更好的方法来做到这一点?感觉不对。让我从新设计开始:

Layout:  Collection -> Document -> Collection -> Documents
  Example Data:
  Stores  -> UID  -> StoresList -> Store1
                                    store_name: 'My Place'
                                   Store2
                                    store_name: 'Bellagio'
                                   Store3
                                    store_name: 'Grand Hotel'

所以您可以看到上面的Store1、Store2 和Store3 是文档,并且它们具有字段,其中一个是store_name。

我正在尝试向用户显示他们在其帐户下拥有的商店列表。我不得不这样做的方式,不知道每个用户可能想要经营多少家商店,如下

storeCount == 0 ? SizedBox()
              :
storeCount == 1 ? Container(
  child: uid == null ? LoadingAnimation() : StreamBuilder(
  stream: Firestore.instance.collection('stores').document(uid).collection('StoresList').document('Store1').snapshots(),
  builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
    if (!snapshot.hasData) {
      return LoadingAnimationBasic();
    }
    if (snapshot.data.data == null) {
      return LoadingAnimationBasic();
    } else {
      return ListView.builder(
    shrinkWrap: true,
      itemCount: 1,
      itemBuilder: (context, index) =>
        _buildStoresList(context, snapshot.data),
       );
     }
   },
 )) :
storeCount == 2 ? Container(
  child: uid == null ? LoadingAnimationBasic() : StreamBuilder(
  stream: Firestore.instance.collection('stores').document(uid).collection('StoresList').document('Store1').snapshots(),
  builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
    if (!snapshot.hasData) {
      return LoadingAnimationBasic();
    }
    if (snapshot.data.data == null) {
      return LoadingAnimationBasic();
    } else {
      return ListView.builder(
        shrinkWrap: true,
        itemCount: 1,
        itemBuilder: (context, index) =>
          _buildStoresList(context, snapshot.data),
        );
      }
    },
  ),
Container(
  child: uid == null ? LoadingAnimationBasic() : StreamBuilder(
  stream: Firestore.instance.collection('stores').document(uid).collection('StoresList').document('Store2').snapshots(),
  builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
    if (!snapshot.hasData) {
      return LoadingAnimationBasic();
    }
    if (snapshot.data.data == null) {
      return LoadingAnimationBasic();
    } else {
      return ListView.builder(
        shrinkWrap: true,
        itemCount: 1,
        itemBuilder: (context, index) =>
          _buildStoresList(context, snapshot.data),
        );
      }
    },
  ),
) : SizedBox(),

然后是 _buildStoresList 函数:

  Widget _buildStoresList(BuildContext context, DocumentSnapshot document) {
    storeName = document['store_name'];
    return Center(
      child: Text(
        storeName,
        style: TextStyle(
          fontFamily: 'Petita',
          color: Colors.black,
          fontSize: 60,
        ),
      ),
    );
  }

所以基本上,首先计算用户拥有的商店数量(通过在 initState() 期间使用 Future.delayed 解决方法计算 StoresList 集合中的文档数量来正确填充它)。一旦我有了商店的数量,我可以看到从每个文档中获取数据的唯一方法是使用可怕的嵌套 if 语句来完成上述操作。

我在这里做错了什么?或者这是唯一的方法吗?

我想主要问题是关于这一行的:

stream: Firestore.instance.collection('stores').document(uid).collection('StoresList').document('Store1').snapshots(),

我需要提供特定文档以便对字段进行快照。使用一行来拍摄集合中所有文档的快照,而不是像这样一次只拍摄一个,效率会无限提高。否则,如果用户想管理 200 家商店,这个“if 语句”嵌套将是疯狂的。

【问题讨论】:

  • 谢谢彼得。我不确定这意味着什么。你说这不可能?如果是这样,我不能接受。这是数据库的一个非常基本的概念,能够检索您输入其中的数据。如果我不能执行这个最基本的功能,那么 Firebase 根本就没有存在的理由。
  • firebase.google.com/docs/firestore/query-data/… 基本上在客户端它不能这样做。您无法获取集合名称列表。商店名称是否属于 uid?
  • 是的,所以基本上 UID 是我区分用户的方式,这是相当教科书。对于每个用户,他们可以根据需要创建和管理任意数量的商店。我正在使用的应用程序部分是将当前商店名称返回给用户的地方。从这一点开始,在每个商店名称下将放置基于数据类别的文档(因为只有文档可以有字段),例如商店信息、产品、图像参考(再一次,firebase 很糟糕,我什至不能返回图像列表)。我不明白他们怎么可能以这种方式设计数据库,这太白痴了。

标签: firebase flutter dart google-cloud-firestore


【解决方案1】:

您需要将数据库更改为以下内容:

Stores (Collection) --> UID (Document) --> Stores (Collection) --> StoreName_1 (Document) 
                                                                   StoreName_2 (Document)

那么你可以这样做:

var documents = await Firestore.instance.collection('Stores').document(widget.currentUserUID).collection("Stores").getDocuments();

这将使您获得一个用户下的所有Stores。

【讨论】:

  • 但是在商店名称下,我需要部分数据。所以在 StoreName1 之后:-> Info -> Field1, Field2, Field3。然后 StoreName1 -> 营业时间 -> 星期一、星期二、星期三。然后是 StoreName1 -> ImageGallery -> URL1、URL2、URL3。
  • 我想如果这是唯一的方法,我将不得不在某些点上随机编造集合名称,这样我就可以将信息推送到文档中。这太疯狂了,但我会试试看。
  • 在 storename1 这是一个文档下,你为什么不能直接添加信息(在该文档的字段中)?你为什么要做一个名为 info 的子集合
  • 因为我不想将 2000 个数据字段集中在一起。这对机器来说可能很好,但这不是有组织的人类思维的运作方式。需要将事物分开并保持整洁、有条理和明智。
  • 您可以在文档中使用数组,因此如果信息始终为 3 个字段,则将其添加到数组中,如果营业时间也可以在数组中。您可以在文档中使用地图和数组
【解决方案2】:

(代表问题作者发布答案,以便将其移至答案空间)。

我已经解决了这个问题,它比我最初尝试的嵌套 if 语句要简单得多。

所以数据库布局完全相同,您只能从文档中提取数据,而不是从集合中提取数据,因此请确保在构建数据库时牢记这一点。

您可以像这样从集合中返回所有文档:

Container(
  child: StreamBuilder(
    stream: Firestore.instance.collection('stores').document(uid).collection('StoresList').snapshots(),
    builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
      if (!snapshot.hasData) {
        return LoadingAnimationBasic();  //This is a custom animation, you can use SizedBox() or anything you like here.
      }
      if (snapshot.data == null) {
        return LoadingAnimationBasic();
      } else {
        return ListView(
          shrinkWrap: true,
          children: _buildStoresList(snapshot),  //Here we are chucking the whole collection snapshot into a ListView builder.  This sends all the documents in the collection in this direction.
        );
      }
    },
  ),
),

然后处理所有这些文档的函数非常简单:

  _buildStoresList(AsyncSnapshot<QuerySnapshot> snapshot) {
    return snapshot.data.documents
        .map((doc) => ListTile(
          title: Center(child: Text(doc['store_name'])),   //store_name is one of the fields inside my documents inside the collection on which I took the snapshots.
          subtitle: Center(child: Text(doc['about']))  //about is another such field.
    ))
        .toList();
  }

就是这样。

【讨论】:

    猜你喜欢
    • 2020-03-21
    • 2019-05-27
    • 2021-03-10
    • 2020-05-15
    • 2021-12-27
    • 2020-12-03
    • 2021-09-28
    • 1970-01-01
    • 2020-01-05
    相关资源
    最近更新 更多