Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you load array and object from Cloud Firestore in Flutter

I have a class that has several embedded arrays as well as a couple of objects. I'm using Flutter and can't figure out how to read/write to Cloud Firestore.

I can read/write data members that are default types like String and Int. Here is the constructor I'm trying to use to instantiate an object from a DocumentSnapshot:

 class GameReview {    String name;    int howPopular;    List<String> reviewers;  }   class ItemCount {    int itemType;    int count;     ItemCount.fromMap(Map<dynamic, dynamic> data)        : itemType = data['itemType'],          count = data['count'];  }   class GameRecord {    // Header members    String documentID;    String name;    int creationTimestamp;    List<int> ratings = new List<int>();    List<String> players = new List<String>();    GameReview gameReview;    List<ItemCount> itemCounts = new List<ItemCount>();     GameRecord.fromSnapshot(DocumentSnapshot snapshot)        : documentID = snapshot.documentID,          name = snapshot['name'],          creationTimestamp = snapshot['creationTimestamp'],          ratings = snapshot['ratings'], // ERROR on run          players = snapshot['players'], // ERROR on run          gameReview = snapshot['gameReview']; // ERROR on run          itemCount = ????  } 

It works until I add the last 3 members (ratings, players and gameReview). This should be obvious but none the less, it eludes me.

Help!

UPDATE: Here is a sample of the document stored in Cloud Firestore. This is stored in a single document. In other words, I'm not using sub-collections for the embedded objects. I put it into a JSON format for clarity. I hope this helps.

 {    "documentID": "asd8didjeurkff3",    "name": "My Game Record",    "creationTimestamp": 1235434,    "ratings": [      4,      2012,      4    ],    "players": [      "Fred",      "Sue",      "John"    ],    "gameReview": {      "name": "Review 1",      "howPopular": 5,      "reviewers": [        "Bob",        "Hanna",        "George"      ]    },   "itemCounts": [      {        "itemType": 2,        "count": 3      },      {        "itemType": 1,        "count": 2      }    ]  } 

UPDATE 2: I didn't put in the whole class definition because I thought it would be obvious to me how to do the rest but alas that was not the case.

I have a list of objects that I want to load.vbandrade's answer is BANG on but I can't quite figure out how I'm supposed to create the list of objects. List.from(...) is looking for an iterator, not a created class. I'm sure it's some variation of creating a new object and then adding it to a list but I'm a little confused. (see edits in class above, specifically, the "itemCounts" member.

like image 845
JustLearningAgain Avatar asked Jun 12 '18 02:06

JustLearningAgain


People also ask

How do you use cloud firestore in Flutter?

How to integrate firebase with flutter android or ios app ? Open firebase, click on get started which will take you to the Add Project screen. Enter the project name and complete the other essential steps. It will take you to your project screen, click on the android icon.


2 Answers

If you came here because of List<dynamic> is not of type List<someType> error while reading data from firestore, you can just use List.castFrom

Example: List<String> cards = List.castFrom(cardsListFromFirebase);

Checkout Flutter firebase, List<dynamic> is not of type List<String>

like image 24
Bhaskar Avatar answered Oct 11 '22 02:10

Bhaskar


load the list from the array and let the framework take care of type casting.

an object is simply a map, like you wrote in your Json. I also use named constructor. ((still learning and dont know how to use the static constructor @ganapat mentioned))

here´s the working code. I kept firebase auth out and used the StreamBuilder widget.

import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'model/firebase_auth_service.dart';  void main() async {   runApp(new MyApp()); }  class MyApp extends StatelessWidget {   final firebaseAuth = new FirebaseAuthService();    MyApp() {     firebaseAuth.anonymousLogin();   }    @override   Widget build(BuildContext context) {     return MaterialApp(         home: Scaffold(             body: Center(                 child: FlatButton(       color: Colors.amber,       child: Column(         mainAxisSize: MainAxisSize.min,         children: <Widget>[           Text("get Game Record"),           StreamBuilder<GameRecord>(             stream: getGame(),             builder: (BuildContext c, AsyncSnapshot<GameRecord> data) {               if (data?.data == null) return Text("Error");                GameRecord r = data.data;                return Text("${r.creationTimestamp} + ${r.name}");             },           ),         ],       ),       onPressed: () {         getGame();       },     ))));   } }  Stream<GameRecord> getGame() {   return Firestore.instance       .collection("games")       .document("zZJKQOuuoYVgsyhJJAgc")       .get()       .then((snapshot) {     try {       return GameRecord.fromSnapshot(snapshot);     } catch (e) {       print(e);       return null;     }   }).asStream(); }  class GameReview {   String name;   int howPopular;   List<String> reviewers;    GameReview.fromMap(Map<dynamic, dynamic> data)       : name = data["name"],         howPopular = data["howPopular"],         reviewers = List.from(data['reviewers']); }  class GameRecord {   // Header members   String documentID;   String name;   int creationTimestamp;   List<int> ratings = new List<int>();   List<String> players = new List<String>();   GameReview gameReview;    GameRecord.fromSnapshot(DocumentSnapshot snapshot)       : documentID = snapshot.documentID,         name = snapshot['name'],         creationTimestamp = snapshot['creationTimestamp'],         ratings = List.from(snapshot['ratings']),         players = List.from(snapshot['players']),         gameReview = GameReview.fromMap(snapshot['gameReview']); } 

snapshot['itemCount'] is an array of objects. map each item in that array to an ItemCount object and return as a List:

    itemCounts = snapshot['itemCount'].map<ItemCount>((item) {       return ItemCount.fromMap(item);     }).toList(); 
like image 180
vbandrade Avatar answered Oct 11 '22 00:10

vbandrade