【问题标题】:How to use Firestore withConverter in Flutter如何在 Flutter 中使用 Firestore withConverter
【发布时间】:2021-09-05 18:44:21
【问题描述】:

我看到最近cloud_firestore: ^2.0.0 更新带来了新的withConverter 功能。

我想用它在 Firestore 中检索和传递我的模型,但我不太确定如何使用现有代码执行此操作。

例如,如何更新以下代码以使用我的自定义模型?

FirebaseFirestore.instance.collection('movies').add({
  'length': 123,
  'rating': 9.7,
});

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore


    【解决方案1】:

    假设您有这样的模型:

    class Movie {
      final int length;
      final double rating;
    
      const Movie({required this.length, required this.rating});
    
      factory Movie.fromJson(Map<String, dynamic> json) => Movie(
            length: json['length'],
            rating: json['rating'],
          );
    
      Map<String, Object?> toJson() => {
            'length': length,
            'rating': rating,
          };
    }
    

    您可以使用withConverter 喜欢:

    void main() async {
      final model = FirebaseFirestore.instance
          .collection('movies')
          .doc()
          .withConverter<Movie>(
        fromFirestore: (snapshot, _) => Movie.fromJson(snapshot.data()!),
        toFirestore: (movie, _) => movie.toJson(),
      );
    
      final movie = Movie(length: 123, rating: 9.7);
      
      // Write operations
      await model.set(movie);
      await model.delete();
      await model.update(newMovie);
    
      // Read operation
      final fetchedMovie = (await model.get()).data();
    }
    

    【讨论】:

      【解决方案2】:

      Firestore 类型

      首先,从 2.0.0 开始,所有 Firestore referencesqueries 现在都是typed。这意味着CollectionReference&lt;T&gt;DocumentReference&lt;T&gt;Query&lt;T&gt; 现在都有一个泛型类型参数T

      默认

      默认情况下(例如调用FirebaseFirestore.instance.collection()时),这个泛型是Map&lt;String, dynamic&gt;。这意味着(无需调用withConverter),您传递的数据和接收的数据始终是Map&lt;String, dynamic&gt; 类型。

      withConverter

      现在,您可以在各个地方使用withConverter更改这种类型:

      final modelRef = FirebaseFirestore.instance
          .collection('models')
          .doc('123')
          .withConverter<Model>(
            fromFirestore: (snapshot, _) => Model.fromJson(snapshot.data()!),
            toFirestore: (model, _) => model.toJson(),
          );
      
      final modelsRef =
          FirebaseFirestore.instance.collection('models').withConverter<Model>(
                fromFirestore: (snapshot, _) => Model.fromJson(snapshot.data()!),
                toFirestore: (model, _) => model.toJson(),
              );
      
      final personsRef = FirebaseFirestore.instance
          .collection('persons')
          .where('age', isGreaterThan: 0)
          .withConverter<Person>(
            fromFirestore: (snapshot, _) => Person.fromJson(snapshot.data()!),
            toFirestore: (model, _) => model.toJson(),
          );
      

      调用withConverter 时发生的情况是通用类型T 设置为您的自定义Model(例如最后一个示例中的Person)。这意味着对文档引用、集合引用或查询的每个后续调用都将使用该类型而不是 Map&lt;String, dynamic&gt;

      用法

      该方法的用法很简单:

      • 您传递了一个 FromFirestore 函数,该函数将快照(带有选项)转换为您的自定义模型。
      • 您传递了一个 ToFirestore 函数,该函数将您的模型 T(带有选项)转换回 Map&lt;String, dynamic&gt;,即特定于 Firestore 的 JSON 数据。

      示例

      这是一个使用 withConverter 和自定义 Movie 模型类的示例(请注意,我使用的是 freezed,因为它更具可读性):

      Future<void> main() async {
        // Create an instance of our model.
        const movie = Movie(length: 123, rating: 9.7);
      
        // Create an instance of a collection withConverter.
        final collection =
            FirebaseFirestore.instance.collection('movies').withConverter(
                  fromFirestore: (snapshot, _) => Movie.fromJson(snapshot.data()!),
                  toFirestore: (movie, _) => movie.toJson(),
                );
        
        // Directly add our model to the collection.
        collection.add(movie);
        // Also works for subsequent calls.
        collection.doc('123').set(movie);
      
        // And also works for reads.
        final Movie movie2 = (await collection.doc('2').get()).data()!;
      }
      
      @freezed
      class Movie with _$Movie {
        const factory Movie({
          required int length,
          required double rating,
        }) = _Movie;
      
        factory Movie.fromJson(Map<String, dynamic> json) => _$MovieFromJson(json);
      }
      

      【讨论】:

      • 如何使用此方法将整个电影集合作为 List 获取?
      猜你喜欢
      • 2022-01-18
      • 2020-12-24
      • 2019-12-01
      • 2021-09-14
      • 2021-09-10
      • 2022-06-13
      • 2018-11-22
      • 2019-10-03
      • 2020-12-12
      相关资源
      最近更新 更多