如何在Flutter中从Cloud Firestore加载数组和对象

Jus*_*ain 9 flutter google-cloud-firestore

我有一类具有几个嵌入式数组以及几个对象的类。我正在使用Flutter,无法弄清楚如何读写Cloud Firestore。

我可以读写默认类型的数据成员,例如String和Int。这是我试图用来从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 = ????
 }
Run Code Online (Sandbox Code Playgroud)

在我添加最后3个成员(评分,玩家和gameReview)之前,它一直有效。这应该很明显,但无论如何,它使我难以理解。

救命!

更新:这是Cloud Firestore中存储的文档的示例。这存储在单个文档中。换句话说,我没有为嵌入式对象使用子集合。为了清楚起见,我将其放入JSON格式。我希望这有帮助。

 {
   "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
     }
   ]
 }
Run Code Online (Sandbox Code Playgroud)

更新2:我没有输入整个类的定义,因为我认为如何进行其余的工作对我来说是显而易见的,但是事实并非如此。

我有一个要加载的对象列表。vbandrade的答案是BANG,但是我不太清楚如何创建对象列表。List.from(...)正在寻找迭代器,而不是创建的类。我敢肯定,创建一个新对象然后将其添加到列表中是一种变化,但是我有些困惑。(请参阅上面的类中的编辑,特别是“ itemCounts”成员。

谢谢!!!

vba*_*ade 13

从数组中加载列表,然后让框架进行类型转换。

一个对象就是一个地图,就像您在Json中编写的一样。我也使用命名构造函数。((仍在学习并且不知道如何使用静态构造函数@ganapat提到))

这是工作代码。我保留了Firebase身份验证,并使用了StreamBuilder小部件。

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']);
}
Run Code Online (Sandbox Code Playgroud)

snapshot['itemCount']是一组对象。将数组中的每个项目映射到一个ItemCount对象,并作为List返回:

    itemCounts = snapshot['itemCount'].map<ItemCount>((item) {
      return ItemCount.fromMap(item);
    }).toList();
Run Code Online (Sandbox Code Playgroud)

  • 花了几个小时...`List&lt;String&gt;.from`正是我将 List&lt;dynamic&gt; 从 firestore 转换为 List&lt;String&gt; 所需要的......希望我能早点找到你的答案 (2认同)

bha*_*kar 12

如果您因为List<dynamic> is not of type List<someType>从 firestore 读取数据时出错而来到这里,您可以使用List.castFrom

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

结帐Flutter firebase,List<dynamic> 不是 List<String> 类型


Mor*_*rad 10

您可以使用JsoSerializable()

将以下依赖项添加到 pubspec.yaml

dependencies:
  # Your other regular dependencies here
  json_annotation: ^2.0.0

dev_dependencies:
  # Your other dev_dependencies here
  build_runner: ^1.0.0
  json_serializable: ^2.0.0
Run Code Online (Sandbox Code Playgroud)

并让你的课程 JsonSerializable()

import 'package:json_annotation/json_annotation.dart';

part 'game.g.dart';

@JsonSerializable()
 class GameReview {
   String name;
   int howPopular;
   List<String> reviewers;

  GameReview();

  factory GameReview.fromJson(Map<String, dynamic> json) => _$GameReviewFromJson(json);

  Map<String, dynamic> toJson() => _$GameReviewToJson(this);
 }

@JsonSerializable()
 class ItemCount {
   int itemType;
   int count;

   ItemCount();

   factory ItemCount.fromJson(Map<String, dynamic> json) => _$ItemCountFromJson(json);

  Map<String, dynamic> toJson() => _$ItemCountToJson(this);
 }

 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();

  factory GameRecord.fromJson(Map<String, dynamic> json) => _$GameRecordFromJson(json);

  Map<String, dynamic> toJson() => _$GameRecordToJson(this);
 }
Run Code Online (Sandbox Code Playgroud)

然后通过从终端运行代码生成实用程序来生成 JSON 序列化代码:

flutter packages pub run build_runner build
Run Code Online (Sandbox Code Playgroud)

现在您可以使用 jsonEncode() 和 jsonDecode() 来存储和检索 firestore 中的对象

设置数据:

Firestore.instance
      .collection("games")
      .document("zZJKQOuuoYVgsyhJJAgc")
      .setData(jsonDecode(jsonEncode(gameRecord)));
Run Code Online (Sandbox Code Playgroud)

用于检索数据:

 GameRecord.fromJson(jsonDecode(jsonEncode(snapshot.data)));
Run Code Online (Sandbox Code Playgroud)


Gan*_*pat 1

Firebase 包返回快照中存在的数组/列表类型的列表类型。在分配给变量之前尝试将 List 转换为 List 或 List。对于 GameReview 对象,当前,您正在尝试将 Map 对象分配给该对象,如果您在 GameReview 类中编写静态 fromMap 方法,该方法接受 Map 参数并将其转换为所需的对象结构,那么这将是有益的,正如您在许多中看到的那样颤振示例代码。

class GameReivew{

  static GameReivew fromMap(Map<String, dynamic> map){
    GameReivew gameReivew = new GameReivew();
    gameReivew.name = map["name"];
    gameReivew.howPopular = map["howPopular"];
    ....

    return gameReivew;
  }
}
Run Code Online (Sandbox Code Playgroud)