简体   繁体   中英

Can't get documents from firestore on flutter

I'm trying to get documents in brews collection from firestore database.

I wrote code like below but it's getting empty array.

What is wrong with my code?

Help me somebody who is used to flutter and firebase.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:brew_crew/models/brew.dart';

class DatabaseService {

  final String uid;
  DatabaseService({ this.uid });

  // collection references
  final CollectionReference brewCollection = FirebaseFirestore.instance.collection("brews");

~~~ short cut ~~~

  // brew list from snapshot
  List<Brew> _brewListFromSnapshot(QuerySnapshot snapshot) {
    print(snapshot.docs.length); // return 0.
    // print(snapshot.docs.toString()); // here this returns [].
    return snapshot.docs.map((doc) {
      return Brew(
        name: doc.data()['name'] ?? '',
        strength: doc.data()['strength'] ?? 0,
        sugars: doc.data()['sugars'] ?? 0,
      );
    }).toList();
  }

  Stream<List<Brew>> get brews {
    return brewCollection.snapshots()
        .map(_brewListFromSnapshot);
  }
}

Added the code using the stream

home.dart

import 'package:brew_crew/screens/services/auth.dart';
import 'package:brew_crew/screens/services/database.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:brew_crew/screens/home/brew_list.dart';

class Home extends StatelessWidget {

  final AuthService _auth = AuthService();

  @override
  Widget build(BuildContext context) {
    return StreamProvider<List<Brew>>.value(
      value: DatabaseService().brews, // here using the stream.
child: Scaffold(

~~~ short cut ~~~

        body: BrewList(), // here too.
      ),
    );
  }
}

This is a file for home screen page and makes DatabaseService instance to call brews stream.

This is passing brews stream as value to Provider and the value is called in BrewList instance in body.

brew_list.dart

import 'package:brew_crew/models/brew.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class BrewList extends StatefulWidget {
  @override
  _BrewListState createState() => _BrewListState();
}

class _BrewListState extends State<BrewList> {
  @override
  Widget build(BuildContext context) {
    final brews = Provider.of<List<Brew>>(context);
    brews.forEach((brew) {
      print(brew.name);
      print(brew.sugars);
    });
    // print(brews.toString()); // here returns [] too.
    return Container();
  }
}

In BrewList class, just calls Provider value.

Added

brew_list.dart

print(brews.length);

returns

Performing hot reload...
Syncing files to device iPhone 8...
flutter: 0
Reloaded 4 of 667 libraries in 253ms.
flutter: 0
flutter: 0

Added

I get this error when using forEach in brew_list.dart.

The following NoSuchMethodError was thrown building BrewList(dirty, dependencies: [_InheritedProviderScope<List<Brew>>], state: _BrewListState#eaba8):
The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (Brew) => Null)

Your Print is trying to convert an array of objects to a string that isn't valid or Stringable since it also contains circular references. However, snapshot.docs are iterable, and using forEach will process each document for your needs.

Just ensure that the snapshot is finalized before processing it by awaiting it or handling it inside your Stream Provider as needed.

You can check the count of the documents with snapshot.docs.length if you are seeing values return, you will have to debug further.

You are receiving that error because you're trying to output data that hasn't yet been completely fetched. Your stream is getting the data from Firestore but it needs time to send it all down. So I recommend using a null-aware operator like ?? or simply check yourself if it's null, if not then show a different widget in the meantime.

final brews = Provider.of<List<Brew>>(context);

    return brews == null ? CircularProgressIndicator() :
          ListView.builder(
            itemCount: brews.length,
            itemBuilder: (context, index) {
              return Text("${brews[index].name}");
            },
          );

Sorry, I noticed that I was mistaking collection name. It was not "brews" but "brew".

Thanks a lot for trying to help me.

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