使用Flutter与Firestore时,如何处理Freezed模型的数据Schema迁移?
惰性处理Freezed Profile模型的Schema迁移
核心想法
惰性迁移的关键是读取旧数据时自动补全缺失字段,仅在用户修改数据时才把更新后的完整Schema写回Firestore,避免一次性全量更新所有旧文档带来的性能开销。
具体实现方案
1. 自定义fromJson方法补全缺失字段
修改ProfileV2的fromJson工厂方法,在调用自动生成的_$ProfileFromJson前,先检查并补全authenticated类型缺失的upvotes字段:
@freezed class Profile with _$Profile { const factory Profile.anonymous({ required String id, }) = _AnonymousProfile; const factory Profile.authenticated({ required String id, required String username, required int upvotes, }) = _AuthenticatedProfile; // 自定义fromJson处理旧数据迁移 factory Profile.fromJson(Map<String, dynamic> json) { // Freezed会用runtimeType标记union类型,据此判断是否为已认证用户 if (json['runtimeType'] == '_AuthenticatedProfile' && !json.containsKey('upvotes')) { // 补全缺失的upvotes,默认值设为0 json = Map<String, dynamic>.from(json)..['upvotes'] = 0; } return _$ProfileFromJson(json); } }
2. 惰性回写更新后的Schema
当用户对Profile进行修改操作(比如更新用户名、增加点赞数)时,再将完整的ProfileV2数据写回Firestore。旧文档只会在用户主动修改时被更新,实现真正的惰性迁移:
// 示例:修改用户名并保存的方法 Future<void> updateUsername(String userId, String newUsername) async { final docRef = FirebaseFirestore.instance.collection('profiles').doc(userId); // 读取旧数据时自动补全upvotes final profile = Profile.fromJson((await docRef.get()).data()!); if (profile is _AuthenticatedProfile) { // 创建包含完整V2字段的新实例 final updatedProfile = profile.copyWith(username: newUsername); // 写回Firestore,完成文档的Schema升级 await docRef.set(updatedProfile.toJson()); } }
3. 可选优化:标记待迁移文档
如果需要跟踪哪些文档还没完成迁移,可以在读取旧数据时给文档加一个needsMigration标记(不强制立即更新),后续可通过后台任务或用户操作批量处理:
factory Profile.fromJson(Map<String, dynamic> json) { bool needsMigration = false; if (json['runtimeType'] == '_AuthenticatedProfile' && !json.containsKey('upvotes')) { json = Map<String, dynamic>.from(json)..['upvotes'] = 0; needsMigration = true; } final profile = _$ProfileFromJson(json); if (needsMigration) { // 给旧文档标记迁移状态,不影响当前读取操作 FirebaseFirestore.instance.collection('profiles').doc((profile as _AuthenticatedProfile).id) .update({'needsMigration': true}); } return profile; }
方案优势
- 读取阶段无额外写操作,不会增加Firestore的负载
- 仅在用户主动修改时才升级文档Schema,避免不必要的资源消耗
- 完全兼容V1和V2数据,不会触发解析错误
内容的提问来源于stack exchange,提问作者Eray Erdin
相关产品推荐
相关产品推荐

