Flutter中使用JsonSerializable创建Firestore子集合的正确方法
在Flutter中结合JsonSerializable使用Firebase Firestore子集合
核心概念说明
Firestore的子集合是独立于父文档的集合,并非父文档的内嵌字段。所以你的AccountModel不需要直接包含子集合的列表数据,而是通过父文档的ID来定位对应的子集合。JsonSerializable仅负责处理文档本身的字段序列化,子集合的操作需要单独处理。
1. 创建子集合对应的模型
分别为用户和狗狗创建独立的模型类,同样使用JsonSerializable注解:
UserModel(用户子集合模型)
import 'package:json_annotation/json_annotation.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; part 'user_model.g.dart'; @JsonSerializable(explicitToJson: true) class UserModel { String userId; String userName; int age; @JsonKey(fromJson: dateTimeFromTimestamp, toJson: dateTimeAsIs) DateTime? joinDate; UserModel({ required this.userId, required this.userName, required this.age, this.joinDate, }); factory UserModel.fromJson(Map<String, dynamic> json) => _$UserModelFromJson(json); Map<String, dynamic> toJson() => _$UserModelToJson(this); static DateTime? dateTimeFromTimestamp(Timestamp? timestamp) { return timestamp?.toDate(); } static Timestamp? dateTimeAsIs(DateTime? dateTime) { return dateTime != null ? Timestamp.fromDate(dateTime) : null; } }
DogModel(狗狗子集合模型)
import 'package:json_annotation/json_annotation.dart'; part 'dog_model.g.dart'; @JsonSerializable(explicitToJson: true) class DogModel { String dogId; String breed; String name; int age; DogModel({ required this.dogId, required this.breed, required this.name, required this.age, }); factory DogModel.fromJson(Map<String, dynamic> json) => _$DogModelFromJson(json); Map<String, dynamic> toJson() => _$DogModelToJson(this); }
2. 完善AccountModel
在AccountModel中添加获取子集合引用的方法(注意:该方法无需序列化,因为Firestore的CollectionReference无法被JsonSerializable处理),同时补全序列化逻辑:
import 'package:json_annotation/json_annotation.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'user_model.dart'; import 'dog_model.dart'; part 'account_model.g.dart'; @JsonSerializable(explicitToJson: true) class AccountModel { String accountId; String accountName; @JsonKey(fromJson: dateTimeFromTimestamp, toJson: dateTimeAsIs) DateTime? createdAt; AccountModel({ required this.accountId, required this.accountName, this.createdAt, }); factory AccountModel.fromJson(Map<String, dynamic> json) => _$AccountModelFromJson(json); Map<String, dynamic> toJson() => _$AccountModelToJson(this); // 获取用户子集合引用 CollectionReference<UserModel> getUsersCollection() { return FirebaseFirestore.instance .collection('accounts') .doc(accountId) .collection('users') .withConverter<UserModel>( fromFirestore: (snapshot, _) => UserModel.fromJson(snapshot.data()!), toFirestore: (user, _) => user.toJson(), ); } // 获取狗狗子集合引用 CollectionReference<DogModel> getDogsCollection() { return FirebaseFirestore.instance .collection('accounts') .doc(accountId) .collection('dogs') .withConverter<DogModel>( fromFirestore: (snapshot, _) => DogModel.fromJson(snapshot.data()!), toFirestore: (dog, _) => dog.toJson(), ); } static DateTime? dateTimeFromTimestamp(Timestamp? timestamp) { return timestamp?.toDate(); } static Timestamp? dateTimeAsIs(DateTime? dateTime) { return dateTime != null ? Timestamp.fromDate(dateTime) : null; } }
3. 子集合读写示例
写入子集合数据
// 实例化账户模型 final account = AccountModel( accountId: 'account_123', accountName: 'My Family Account', createdAt: DateTime.now(), ); // 写入用户到子集合 final user = UserModel( userId: 'user_456', userName: 'John Doe', age: 30, joinDate: DateTime.now(), ); await account.getUsersCollection().doc(user.userId).set(user); // 写入狗狗到子集合 final dog = DogModel( dogId: 'dog_789', breed: 'Golden Retriever', name: 'Buddy', age: 2, ); await account.getDogsCollection().doc(dog.dogId).set(dog);
读取子集合数据
// 获取账户下所有用户 final usersSnapshot = await account.getUsersCollection().get(); final users = usersSnapshot.docs.map((doc) => doc.data()).toList(); // 获取账户下所有狗狗 final dogsSnapshot = await account.getDogsCollection().get(); final dogs = dogsSnapshot.docs.map((doc) => doc.data()).toList();
关键注意点
- 子集合不会随父文档删除自动删除,需手动处理删除逻辑。
- 使用
withConverter可直接在集合引用中绑定模型,省去手动序列化/反序列化步骤。 - 父模型的
accountId必须准确,否则无法定位到对应子集合。
内容的提问来源于stack exchange,提问作者Almog
相关产品推荐
相关产品推荐

