简体   繁体   中英

How to get a list of collections and a list of all fields under a collection from Firestore on Flutter?

I'm making a conversation starter app and inside this app, there are different categories of questions a user can choose from. This is how the home page of the app looks like after the user logs in:

应用程序主页的图像

The way I'm currently listing all these categories is by saving the category names as the document ID's under a collection I call 'users'. Then I use the following snippet of code to get all these document IDs/ categories and add them to a List . I then use a FutureBuilder to convert this List<String> to a List of buttons. The code below can help clarify what I am doing:

Step 1: get all document IDs/category names:

  List<String> questionCategories = [];


 Future getCategories() async {
    await FirebaseFirestore.instance
        .collection('users')
        .get()
        .then((snapshot) => snapshot.docs.forEach(
              (document) {
                questionCategories.add(document.reference.id);
            ));
  }

Step 2: Use the questionCategories List<String> to create a List of buttons

 FutureBuilder(
            future: getCategories(),
            builder: (context, snapshot) {
              return SizedBox(
                height: MediaQuery.of(context).size.height - 250,
                child: ListView.builder(
                  itemCount: questionCategories.length,
                  itemBuilder: (context, index) {
                    return Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: GestureDetector(
                          onTap: //questionPageInit,
                              () {
                            print(collectionList);
                            Navigator.push(context,
                                MaterialPageRoute(builder: (context) {
                              //return ForgotPasswordPage();
                              return CategoryPage(
                                categoryName: questionCategories[index],
                              );
                            }));
                          },
                          child: Container(
                              padding: EdgeInsets.all(20),
                              decoration: BoxDecoration(
                                color: Colors.deepPurple,
                                borderRadius: BorderRadius.circular(12),
                              ),
                              child: Center(
                                  child: Text(questionCategories[index],
                                      style: TextStyle(
                                        color: Colors.white,
                                        fontWeight: FontWeight.bold,
                                        fontSize: 18,
                                      ))))),
                    );
                  },
                ),
              );
            },
          ),

Upon picking a category, questions are displayed one at a time on a question card, wherein below this card a user can switch between the next and previous questions and then shuffle. This page looks like so:

应用问题页面的图片

The way I'm getting these questions displayed is by getting a List of all the fields under a document ID and adding it to a List<String> . When the user presses shuffle, next, or previous, I just change a global index variable and set the state again to display a new question based on which question appears to be at that specific index in the List . The following code should help clarify what I am doing:

void printAllQuestionsList(snapshot) {
    Map<String, dynamic> data = snapshot.data() as Map<String, dynamic>;
    for (String key in data.keys) {
      print(key + data[key]!);
      questionsList.add(data[key]);
    }
  }

  Future getQuestionList() async {
    if (questIndex > 1) {
      return;
    }
    if (widget.categoryName == "ALL") {
      await FirebaseFirestore.instance
          .collection('users')
          .get()
          .then(((snapshot) => snapshot.docs.forEach((document) {
                print(document.reference.id);
                FirebaseFirestore.instance
                    .collection('users')
                    .doc(document.reference.id)
                    .get()
                    .then((snapshot) => {printAllQuestionsList(snapshot)});
              })));
    } else {
      await FirebaseFirestore.instance
          .collection('users')
          .doc(widget.categoryName)
          .get()
          .then((snapshot) => {printQuestionList(snapshot)});
    }
  }

Inside the widget Build function, I have this snippet of code:

FutureBuilder(
                    future: getQuestionList(),
                    builder: ((context, snapshot) {
                      // return TextField(
                      //   decoration: InputDecoration(
                      //     enabledBorder: OutlineInputBorder(
                      //       borderSide: BorderSide(
                      //         width: 5, //<-- SEE HERE
                      //         color: Colors.greenAccent,
                      //       ),
                      //       borderRadius: BorderRadius.circular(50.0),
                      //     ),
                      //   ),
                      // );f
                      return Container(
                          margin: const EdgeInsets.all(15.0),
                          padding: const EdgeInsets.all(10.0),
                          width: 350,
                          height: 350,
                          decoration: BoxDecoration(
                              color: Colors.deepPurple[200],
                              borderRadius:
                                  BorderRadius.all(Radius.circular(20))
                              // border: Border.all(color: Colors.blueAccent)
                              ),
                          child: Align(
                            alignment: Alignment.center,
                            child: SingleChildScrollView(
                              scrollDirection: Axis.vertical,
                              child: Text(
                                questionsList[index],
                                style: TextStyle(
                                  color: Colors.white,
                                  fontWeight: FontWeight.bold,
                                  fontSize: 32,
                                ),
                                textDirection: TextDirection.ltr,
                                textAlign: TextAlign.center,
                              ),
                            ),
                          ));
                    }))

I have a second page on this app that is used to submit questions to an existing or new Category (if they enter the right password that I set).

提交问题页面的图像

I use the following snippet of code to do so:

  Future addQuestion(String category, String question) async {
    var usersRef = questionCollection.doc(category);

    await FirebaseFirestore.instance
        .collection('users')
        .get()
        .then((snapshot) => snapshot.docs.forEach(
              (document) {
                existingQuestionCategories.add(document.reference.id);
              },
            ));

    if (existingQuestionCategories.contains(category)) {
      print("Document Exists! ");
      questionCollection.doc(category).update({question: question});
    } else {
      // FieldPath pathfield = FieldPath.fromString(category);
      //String category2 = pathfield.category;
      print('No such document exists so now about to set document anew!');
      print(category);
      FirebaseFirestore.instance
          .collection("users")
          .doc(category)
          .set({question: question});
    }
  }

Here's how my Firestore database is organized

Firestore 数据库组织的图像

Users -> Question Categories (Document IDs) -> question Key: question field

This is how I want to set it up:

Users -> Autogenerated ID -> Question Categories as collections -> question key (titled “question”): question key (“the actual question here)

This way under each collection I can also list fields pertaining to the question like if it's light, medium, or deep that I may be able to add on to later.

I also want to do it this way because sometimes when I try to use my submit question page, the question I type does not get submitted and I think it may be because I'm submitting the question under a document ID and not under a collection.

In summary, my question to you is how do I list all the questions on my home page as a list of collections from my database? Also, how would this change the code I wrote to (1) view the questions on individual cards when clicking a category name and (2) submit new questions to a specific category/collection? If what I'm trying to do cannot be done in the way I want it done, is there a more efficient way to do this?

I tried searching for how to get a list of collections on Firestore on Flutter but all the answers I found gave me a solution on how to get a List of fields under a document ID. This is why I'm asking this question.

Actually the Firebase SDK for Flutter ( and I'm assuming that for Android/IOS) doesn't have any pre-built methods to get a List of all collections in the firestore database.

But, as I know you can get them with a cloud function written as example with Node.js , refer to this and this .

if you're willing to write a cloud function to achieve this on your flutter project, then it's fine.

However, I can think about a practical solution, if that interest's you:

  • Create another collection/document where you list your firestore collections, for your precedent collections, I guess you have no option but to add them manually, but if you're creating new collections for the future in your project, you can implement general methods that check for the existence of a collection name, and act based on it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM