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

Posted

技术标签:

【中文标题】使用 Stream 从 FireStore 获取数据并将其映射到 Flutter 类【英文标题】:Getting data from FireStore using Stream and Map it to Class Flutter 【发布时间】:2020-04-03 04:52:36 【问题描述】:

我正在尝试将 Firestore Map 中的数据反序列化为一个新类并使用 Provider 调用该类。我遵循了几个教程 (https://fireship.io/lessons/advanced-flutter-firebase/) 都没有成功。

///auth_class.dart
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class UserCheck extends ChangeNotifier 
  final _auth = FirebaseAuth.instance;
  FirebaseUser loggedInUser;

  var userDetails;
  final String id;
  String firstName;
  final String lastName;
  final String userEmail;
  final String userOrg;
  final Timestamp regDate;
  final String date;

  UserCheck(
    this.id,
    this.firstName,
    this.lastName,
    this.userEmail,
    this.userOrg,
    this.regDate,
    this.date,
  );

  factory UserCheck.fromSnap(DocumentSnapshot ds) 
    Map data = ds.data;

    return UserCheck(
      id: ds.documentID,
      firstName: ds['fname'] ?? '',
      lastName: data['lname'] ?? '',
      userEmail: data['regEmail'] ?? '',
      userOrg: data['org'] ?? '',

    );
  

然后我尝试使用

调用
//database_service.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:oast_app/widgets/auth_class.dart';

class DatabaseService 

    Stream<List<UserCheck>> streamUser(FirebaseUser user)
    var ref = Firestore.instance.collection('users').document('$user.uid').snapshots();
    return ref.map((list) => 
      return list.data.map((ds) => UserCheck.fromSnap(ds)).toList()
    );
    

错误信息: UserCheck.fromSnap(ds)).toList() ^^^^^^ lib/widgets/database_service.dart:12:55:错误:参数类型“字符串”不能分配给参数类型“文档快照”。 - 'DocumentSnapshot' 来自'package:cloud_firestore/cloud_firestore.dart' ('../../Downloads/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.12.11/lib/cloud_firestore.镖')。 返回 list.data.map((ds) => UserCheck.fromSnap(ds)).toList() ^ lib/widgets/database_service.dart:12:46:错误:“UserCheck”类型的值不能分配给“MapEntry”类型的变量。 - 'UserCheck' 来自'package:oast_app/widgets/auth_class.dart' ('lib/widgets/auth_class.dart')。 - 'MapEntry' 来自'dart:core'。 返回 list.data.map((ds) => UserCheck.fromSnap(ds)).toList() ^ lib/widgets/database_service.dart:12:28:错误:不能将参数类型“MapEntry Function(String)”分配给参数类型“MapEntry Function(String, dynamic)”。 - 'MapEntry' 来自'dart:core'。 返回 list.data.map((ds) => UserCheck.fromSnap(ds)).toList() ^ lib/widgets/database_service.dart:12:60:错误:没有为类“Map”定义方法“toList”。 - “地图”来自“飞镖:核心”。 尝试将名称更正为现有方法的名称,或定义名为“toList”的方法。 返回 list.data.map((ds) => UserCheck.fromSnap(ds)).toList() ^^^^^^ lib/widgets/database_service.dart:11:30:错误:“Set”类型的值不能分配给“List”类型的变量。 - 'Set' 来自 'dart:core'。 - “列表”来自“飞镖:核心”。 - 'UserCheck' 来自'package:oast_app/widgets/auth_class.dart' ('lib/widgets/auth_class.dart')。 返回 ref.map((list) => >

【问题讨论】:

【参考方案1】:

只是一个猜测,你下面的代码不应该;

firstName: ds['fname'] ?? '',

成为

firstName: data['fname'] ?? '',

改为?

【讨论】:

im 关注从 firestore 返回的内容,用户的名字存储为“fname” 您的错误显示“参数类型 'String' 不能分配给参数类型 'DocumentSnapshot'”。你的名字需要一个字符串。但取而代之的是一个 DocumentSnapshot。因此,要从文档快照中获取字符串,它将是 data['fname'] 基于您的代码。【参考方案2】:

您需要使用.data(); 而不是使用.data; 来实际获取文档数据。

但是您可以使用.data().map['[FIELD_NAME]']直接获取Firestore映射的每个值

如前所述,firstName 的部分也应该是 data['fname']。

【讨论】:

【参考方案3】:

你可以使用异步映射

Stream<FirestoreResponse> getStream(String collection) 
    var snapshots =
        FirebaseFirestore.instance.collection(collection).snapshots();
    return snapshots.asyncMap((event) => FirestoreResponse(
        event.docs, event.docChanges, event.metadata, event.size));

使用这样的模型

class FirestoreResponse extends Equatable 
  /// Gets a list of all the documents included in this snapshot.
  final List<QueryDocumentSnapshot<Map<String, dynamic>>> docs;

  /// An array of the documents that changed since the last snapshot. If this
  /// is the first snapshot, all documents will be in the list as Added changes.
  final List<DocumentChange<Map<String, dynamic>>> docChanges;

  /// Returns the [SnapshotMetadata] for this snapshot.
  final SnapshotMetadata metadata;

  /// Returns the size (number of documents) of this snapshot.
  final int size;

  /// Constructor
  const FirestoreResponse(this.docs, this.docChanges, this.metadata, this.size);

  @override
  List<Object?> get props => [
        docs,
        docChanges,
        metadata,
        size,
      ];

【讨论】:

以上是关于使用 Stream 从 FireStore 获取数据并将其映射到 Flutter 类的主要内容,如果未能解决你的问题,请参考以下文章

Flutter - 从 Stream 接收然后修改数据

Firestore 查询流和获取之间的区别?

Flutter,是不是可以在没有小部件构建方法的情况下在功能中使用 Firestore Stream Builder?

Flutter 使用 Stream 检索 Firestore 集合

从 Stream 检索快照时,Flutter/Firestore 返回类型 List<Review> 不是“Map<String, dynamic>”类型的子类型

在 Flutter 列表视图中删除 Firestore 数据