如何在 Firebase + Firestore + Flutter 中使用 StreamBuilder 将所有子集合数据获取到 Widget

Posted

技术标签:

【中文标题】如何在 Firebase + Firestore + Flutter 中使用 StreamBuilder 将所有子集合数据获取到 Widget【英文标题】:How to get all sub collection data to Widget with StreamBuilder in Firebase + Firestore + Flutter 【发布时间】:2021-10-03 20:18:42 【问题描述】:

在 Flutter 中,我使用 Firebase Firestore 来保存数据。我将根集合创建为 Users,在该集合中,每个用户都有一个以 Books 命名的子集合。

这是我的 Firebase Cloud Firestore

我尝试通过如下按钮点击让所有用户获得所有书籍

getUserBooks() 
  FirebaseFirestore.instance.collection("Users").get().then((querySnapshot) 
    querySnapshot.docs.forEach((result) 
      FirebaseFirestore.instance
          .collection("Users")
          .doc(result.id)
          .collection("Books")
          .get()
          .then((querySnapshot) 
        querySnapshot.docs.forEach((result) 
          BooksModel booksModel = BooksModel.fromDocument(result);

          print("--------------------- Books ---------------------\n"
              "id: $booksModel.bookID\n"
              "name: $booksModel.bookName\n"
              "image: $booksModel.bookImage");
        );
      );
    );
  );

这是模型类

class BooksModel 
  final String bookID;
  final String bookName;
  final String bookImage;

  BooksModel(
    this.bookID,
    this.bookName,
    this.bookImage,
  );

  factory BooksModel.fromDocument(DocumentSnapshot documentSnapshot) 
    return BooksModel(
      bookID: documentSnapshot['bookID'],
      bookName: documentSnapshot['bookName'],
      bookImage: documentSnapshot['bookImage'],
    );
  

我使用以下代码根据单个用户获取图书详细信息,但我希望将所有用户的图书详细信息获取到该小部件。如何更改代码?

_usersBookListWidget() 
  return Container(
    height: MediaQuery.of(context).size.height,
    child: StreamBuilder<QuerySnapshot>(
      stream: FirebaseFirestore.instance
          .collection("Users")
          .doc(userID)
          .collection('Books')
          .snapshots(),
      builder: (context, snapshot) 
        return !snapshot.hasData
            ? Container()
            : snapshot.data.docs.length.toString() == "0"
            ? Container(
          height: 250.0,
          width: 200.0,
          child: Column(
            children: [
              SizedBox(
                height: 30.0,
              ),
              Text(
                "You have no books yet",
                style: TextStyle(
                    fontSize: Theme.of(context)
                        .textTheme
                        .headline6
                        .fontSize),
              ),
              Image.asset(
                'assets/icons/icon_no_books_yet.png',
                height: 100.0,
                width: 100.0,
              ),
            ],
          ),
        )
            : ListView.builder(
          scrollDirection: Axis.vertical,
          physics: BouncingScrollPhysics(),
          itemCount: snapshot.data.docs.length,
          itemBuilder: (BuildContext context, int index) 
            BooksModel booksModel =
            BooksModel.fromDocument(snapshot.data.docs[index]);
            return Column(
              children: [
                Text(booksModel.bookID),
                Text(booksModel.bookName),
              ],
            );
          ,
        );
      ,
    ),
  );

【问题讨论】:

【参考方案1】:

目前还没有一种直接的方法来获取单个集合中所有文档的所有子集合,就像您的情况一样。 首先,您必须查询您的 users 集合,然后,对于每个用户文档,您运行一个单独的查询。这是一个伪代码:

1- StreamBuilder (FirebaseFirestore.instance.collection.('Users').snapshots(), 在这里,您可以根据需要在列表视图中显示有关每个用户的信息,但您必须捕获document.id,因为下一步将需要它。

2- 例如,您创建一个名为 userBooks 的小部件,对于此小部件,您将上一步中的 document.id 传递给它。现在您在数据库中拥有了所有用户 ID,并且由于子集合称为 books 并且不会更改,因此您将其用于另一个流构建器,并带有此集合引用: FirebaseFirestore.instance.collection.('Users').doc(document.id).collection('Books').snapshots()。这会给你想要的结果。


为了让你的代码 sn-p 工作,你需要使用 async\await,像这样:

getUserBooks() async 
  await FirebaseFirestore.instance.collection("Users").get().then((querySnapshot) async 
    querySnapshot.docs.forEach((result) 
     await FirebaseFirestore.instance
          .collection("Users")
          .doc(result.id)
          .collection("Books")
          .get()
          .then((querySnapshot) 
        querySnapshot.docs.forEach((result) 
          BooksModel booksModel = BooksModel.fromDocument(result);

          print("--------------------- Books ---------------------\n"
              "id: $booksModel.bookID\n"
              "name: $booksModel.bookName\n"
              "image: $booksModel.bookImage");
        );
      );
    );
  );

这将有助于将它们放在一个按钮中。

【讨论】:

感谢您的想法..我会尝试实现这个答案❤?? 查看编辑后的回复,它适用于您现有的功能getUserBooks()

以上是关于如何在 Firebase + Firestore + Flutter 中使用 StreamBuilder 将所有子集合数据获取到 Widget的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 中使用 Firebase Auth 和 Firestore

如何将图像上传到firebase存储然后将图像url存储在firestore中?

如何使用firebase-admin在firestore中将日期保存为时间戳?

如何在 Firebase Firestore 中获取内部集合

如何在 Swift 上将具有自定义 ID 的文档添加到 Firebase (Firestore)

如何将我的 Firebase 实时数据库转移到 Firebase Cloud Firestore