Firestore 类型
首先,从 2.0.0 开始,所有 Firestore references 和 queries 现在都是typed。这意味着CollectionReference<T>、DocumentReference<T> 和Query<T> 现在都有一个泛型类型参数T。
默认
默认情况下(例如调用FirebaseFirestore.instance.collection()时),这个泛型是Map<String, dynamic>。这意味着(无需调用withConverter),您传递的数据和接收的数据始终是Map<String, dynamic> 类型。
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<String, dynamic>。
用法
该方法的用法很简单:
- 您传递了一个
FromFirestore 函数,该函数将快照(带有选项)转换为您的自定义模型。
- 您传递了一个
ToFirestore 函数,该函数将您的模型 T(带有选项)转换回 Map<String, dynamic>,即特定于 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);
}