Как вы загружаете массив и объект из Cloud Firestore во Flutter? - PullRequest
0 голосов
/ 12 июня 2018

У меня есть класс, который имеет несколько встроенных массивов, а также пару объектов.Я использую 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 = ????
 }

Он работает до тех пор, пока я не добавлю последние 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
     }
   ]
 }

ОБНОВЛЕНИЕ 2: Я не включил полное определение класса, потому что думал, что для меня будет очевидно, как делать все остальное, но, увы, это не так.

У меня есть список объектов, которые я хочу загрузить. Ответ vbandrade на BANG, но я не могу понять, как я должен создать список объектов.List.from (...) ищет итератор, а не созданный класс.Я уверен, что это какой-то вариант создания нового объекта и добавления его в список, но я немного запутался(см. правки в классе выше, в частности член "itemCounts".

Спасибо !!!

Ответы [ 3 ]

0 голосов
/ 15 июня 2018

загрузите список из массива и позвольте фреймворку позаботиться о приведении типов.

объект - это просто карта, как вы написали в своем 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']);
}

snapshot['itemCount'] - массив объектов.сопоставить каждый элемент в этом массиве с объектом ItemCount и вернуть в виде списка:

    itemCounts = snapshot['itemCount'].map<ItemCount>((item) {
      return ItemCount.fromMap(item);
    }).toList();
0 голосов
/ 26 апреля 2019

Вы можете использовать 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

и сделать ваши классы 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);
 }

Затем сгенерируйте код сериализации JSON, запустив на своем терминале утилиту генерации кода:

flutter packages pub run build_runner build

Теперь вы можете использовать jsonEncode () и jsonDecode () для хранения и извлечения объектов из пожарного хранилища.

Для настройки данных:

Firestore.instance
      .collection("games")
      .document("zZJKQOuuoYVgsyhJJAgc")
      .setData(jsonDecode(jsonEncode(gameRecord)));

Для получения данных:

 GameRecord.fromJson(jsonDecode(jsonEncode(snapshot.data)));
0 голосов
/ 15 июня 2018

Пакеты Firebase возвращают типы списков для типов массивов / списков, представленных в снимке.Попробуйте преобразовать список в список или список перед назначением переменных.А для объекта GameReview в настоящее время вы пытаетесь назначить объект Map объекту, было бы полезно, если бы вы написали статический метод fromMap в классе GameReview, который принимает аргумент map и конвертирует его в желаемую структуру объекта, как вы видели бы во многихпримеров кода флаттеров.

class GameReivew{

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

    return gameReivew;
  }
}
...