如何将数据从 Firestore 映射到列表并转换为对象数据类型

Posted

技术标签:

【中文标题】如何将数据从 Firestore 映射到列表并转换为对象数据类型【英文标题】:How to map data from Firestore to a list and convert to object data type 【发布时间】:2021-05-04 13:48:53 【问题描述】:

我正在尝试将来自 firestore QueryDocumentSnapshot 类型的数据映射到自定义 ClassObject 但没有成功

这是我的课

class Food 
 String name;
 int price;
 String image;

  Food(this.name, this.price, this.image, );

下面的示例我在本地制作数据并获取它工作正常

     List<Food> foodType1Local = [
        Food(
          name: 'Food 1',
          price: 10,
          image: 'assets/food1.png',
        ),
        Food(
          name: 'Food 2',
          price: 20,
          image: 'assets/food2.png',
        ),
        Food(
          name: 'Food 3',
          price: 30,
          image: 'assets/food3.png',
        ),
      ];
     List<Food> foodType2Local...
     List<Food> foodType3Local...

下面的示例我在 Cloud Firestore 中制作了数据并获取它是一个问题

下面的示例我正在从 Cloud Firestore 获取数据,但我收到错误 type 'QueryDocumentSnapshot' is not a subtype of type 'Food'

  List foodType1Cloud = <Food>[];
  List foodType2Cloud = <Food>[];
  List foodType3Cloud = <Food>[];

  getFoodType1Cloud() async 
    QuerySnapshot snapshot = await FirebaseFirestore.instance.collection("foodType1").get();
      foodType1Cloud.addAll(snapshot.docs);
      foodType1Cloud.map((foodType1Data) 
        Food(
          name: foodType1Data['name'], //cant do --> name: foodType1Data[index]['name'],
          price: foodType1Data['price'], //cant do --> price: foodType1Data[index]['price'],
          image: foodType1Data['image'], //cant do --> image: foodType1Data[index]['image'],
        );
      ).toList();
  
  getFoodType2Cloud()...
  getFoodType3Cloud()...

这是代码的主体,如果我尝试从 本地数据 获取它可以正常工作,但当我从云 Firestore 获取时不起作用

   //tabs of length "3"
   body: TabBarView(
     children: [
       Container(
         margin: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
         child: Column(
           children: <Widget>[
             buildFoodList(foodType1Local),
           ],
         ),
       ),
       Container(
         margin: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
         child: Column(
           children: <Widget>[
             buildFoodList(foodType1Loca2),
           ],
         ),
       ),
       Container...
       
     ],
   ),

这里是代码的主体,但如果我尝试从 cloud firestore 获取,它会显示错误 type 'QueryDocumentSnapshot' is not a subtype of type 'Food'

        body: TabBarView(
          children: [
            Container(
              margin: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
              child: Column(
                children: <Widget>[
                  buildFoodList(foodType1Cloud),
                ],
              ),
            ),
            Container(
              margin: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
              child: Column(
                children: <Widget>[
                  buildFoodList(foodType2Cloud),
                ],
              ),
            ),
            Container...

          ],
        ),

我认为buildFoodList 代码也是必要的,所以我添加了它以防万一

Widget buildFoodList(List foods) 
    return Expanded(
      child: GridView.builder(
        itemCount: foods.length,
        physics: BouncingScrollPhysics(),
        gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          childAspectRatio: 0.8,
          mainAxisSpacing: 20,
          crossAxisSpacing: 20,
        ),
        itemBuilder: (context, index) 
          return FoodCard(foods[index]);
        ,
      ),
    );
  

【问题讨论】:

【参考方案1】:

snapshot.docs 返回 QuerySnapshot 中所有文档的 ann 数组,显然它不是 Food 的类型。

现在,您必须遍历文档数组并使用提供此快照的所有数据的 data 成员。使用该数据,您可以将其转换为您希望的任何类型的实例。

所以,而不是这个

foodType1Cloud.addAll(snapshot.docs);

将文档内容转换为您的自定义对象并将其添加到列表中

snapshot.docs.forEach(doc => 
   Map<String, dynamic> obj = doc.data;
  // convert this Map to your custom object and add it to your list
);

在flutter中,你可以使用json_serializable进行这个转换!

类似的 SO 参考 - How do you load array and object from Cloud Firestore in Flutter

【讨论】:

【参考方案2】:

第 1 步:

class Employee 
  Employee(this.employeeID, this.employeeName, this.branch, this.designation, this.location,
      this.salary,
      this.reference);

  double employeeID;

  String employeeName;

  String designation;

  String branch;

  String location;

  double salary;

  DocumentReference reference;

  factory Employee.fromSnapshot(DocumentSnapshot snapshot) 
    Employee newEmployee = Employee.fromJson(snapshot.data());
    newEmployee.reference = snapshot.reference;
    return newEmployee;
  

  factory Employee.fromJson(Map<String, dynamic> json) =>
      _employeeFromJson(json);

  Map<String, dynamic> toJson() => _employeeToJson(this);

  @override
  String toString() => 'employeeName $employeeName';


Employee _employeeFromJson(Map<String, dynamic> data) 
  return Employee(
    data['employeeID'],
    data['employeeName'],
    data['branch'],
    data['designation'],
    data['location'],
    data['salary'],
  );


Map<String, dynamic> _employeeToJson(Employee instance) 
  return 
    'employeeID' : instance.employeeID,
    'employeeName': instance.employeeName,
    'branch': instance.branch,
    'designation': instance.designation,
    'location': instance.location,
    'salary': instance.salary,
  ;

第 2 步:

传递 AsyncSnapShot 并将数据构建为列表

List<Employee> employees = [];

Future<void> buildData(AsyncSnapshot snapshot) async 
    if (snapshot.data.documents.length == 0) 
      employees = [];
    

    employees = [];
    await Future.forEach(snapshot.data.documents, (element) 
      employees.add(Employee.fromSnapshot(element));
    );
  

【讨论】:

以上是关于如何将数据从 Firestore 映射到列表并转换为对象数据类型的主要内容,如果未能解决你的问题,请参考以下文章

如何将一组地图从 Firestore 映射到 recyclerView?

如何将数据从 Firestore 检索到我的列表

使用 Stream 从 FireStore 获取数据并将其映射到 Flutter 类

使用云功能时,来自 Firestore 的时间戳会转换为地图

如何将我的数据从 Firestore 转换为身份验证用户

Flutter - 如何从 Firestore 中检索 ID 列表并在 GridView 中显示它们的项目?