Flutter中Firestore JSON转Map<String, Model>解码失败问题
问题解决:Firestore中Map类型字段的序列化/反序列化错误
问题背景
我定义了包含Map<String, UserSportAttributes>类型字段的UserData模型类,使用jsonEncode将数据存入Firebase Firestore时,Firebase控制台显示数据正常,但尝试通过jsonDecode将数据转回UserData模型时持续报错,试了多种解码方式都没解决。
相关代码
UserData 类
import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:sportmate/Models/user_sport_attributes.dart'; class UserData { final String name; final int age; final bool sex; //0 代表男性,1 代表女性 final GeoPoint location; final String bio; final Map<String, UserSportAttributes> sportsPlayed; final bool hasSetupAccount; UserData({ required this.name, required this.age, required this.sex, required this.location, required this.bio, required this.sportsPlayed, required this.hasSetupAccount, }); Map<String, dynamic> toJson() => { 'Name': name, 'Age': age, 'Sex': sex, 'Location': location, 'Biography': bio, 'SportsPlayed': jsonEncode(sportsPlayed), // 会自动调用toJson吗? 'HasSetupAccount': hasSetupAccount, }; static fromJson(Map<String, dynamic> json) { Map<String, dynamic> sportsPlayedJson = jsonDecode(json['SportsPlayed']); return UserData( name: json['Name'], age: json['Age'], sex: json['Sex'], location: json['Location'], bio: json['Biography'], sportsPlayed: Map<String, UserSportAttributes>.from( sportsPlayedJson.map((key, value) => MapEntry(key, UserSportAttributes.fromJson(value)))), hasSetupAccount: json["HasSetupAccount"]); } }
UserSportAttributes 类
class UserSportAttributes { final int level; final bool playedProfessional; final int yearsOfExperience; UserSportAttributes({ required this.level, required this.playedProfessional, required this.yearsOfExperience, }); Map<String, dynamic> toJson() => { 'Level': level, 'PlayedProfessional': playedProfessional, 'YearsOfExperience': yearsOfExperience, }; static fromJson(Map<String, dynamic> json) { return UserSportAttributes( level: json['Level'], playedProfessional: json['PlayedProfessional'], yearsOfExperience: json['YearsOfExperience']); } }
问题根源及解决方案
你的问题出在toJson方法对sportsPlayed的处理上:Firestore本身支持存储嵌套的Map结构,不需要手动用jsonEncode把它转成字符串。你现在的操作是把Map<String, UserSportAttributes>序列化成JSON字符串存在Firestore里,反序列化时又要把字符串转成Map,这个过程中容易出现类型不匹配或者解析错误。
修改步骤:
- 修改UserData的toJson方法:去掉
jsonEncode,直接把sportsPlayed转成嵌套Map——因为UserSportAttributes有自己的toJson方法,Dart会自动递归处理:
Map<String, dynamic> toJson() => { 'Name': name, 'Age': age, 'Sex': sex, 'Location': location, 'Biography': bio, 'SportsPlayed': sportsPlayed.map((key, value) => MapEntry(key, value.toJson())), 'HasSetupAccount': hasSetupAccount, };
- 修改UserData的fromJson方法:不需要再调用
jsonDecode,直接从Firestore返回的Map中解析嵌套结构:
static UserData fromJson(Map<String, dynamic> json) { return UserData( name: json['Name'], age: json['Age'], sex: json['Sex'], location: json['Location'], bio: json['Biography'], sportsPlayed: Map<String, UserSportAttributes>.from( json['SportsPlayed'].map((key, value) => MapEntry(key, UserSportAttributes.fromJson(value as Map<String, dynamic>)))), hasSetupAccount: json["HasSetupAccount"]); }
(注意:这里给fromJson方法加上了返回类型UserData,让代码更规范;同时给value加上了类型断言as Map<String, dynamic>,避免类型警告)
- 清理Firestore中的旧数据:因为之前存的是JSON字符串格式的
SportsPlayed,需要删掉旧数据或者重新写入新格式的数据,否则反序列化还是会报错。
这样修改后,Firestore会存储嵌套的Map结构,反序列化时直接解析即可,不需要额外的JSON字符串转义,就能解决报错问题。
内容的提问来源于stack exchange,提问作者Jaime Ferreira
相关产品推荐
相关产品推荐

