Flutter & Dart 如何从Firestore获取Map类型字段数据

问题复现
业务中Map键为动态值,无法预先定义实体类配合fromJson解析,代码中定义字段:
Map<String, double> rating;
写入数据时以下代码可正常执行:
data['rating'] = json.encode(this.rating);
读取数据时执行以下代码报错:
rating = jsonDecode(json['rating']);
抛出运行时错误:
Expected a value of type 'Map<String, double>', but got one of type 'String'
问题根因
- 写入时你主动调用
json.encode()将Map序列化成了字符串格式存储,读取时如果没有先把字符串从存储对象中取出做解码,直接操作会拿到String类型值,和Map<String, double>类型不匹配。 - 即便正确调用
jsonDecode,Dart默认的JSON解析结果为Map<dynamic, dynamic>类型,无法直接赋值给强类型的Map<String, double>,隐式转换不会生效,同样会抛出类型错误。
正确实现方案
方案1:保留现有写入逻辑,读取时做完整类型转换
如果你的存储层只能存储字符串类型,必须用json.encode序列化写入,读取时按以下步骤处理即可:
// 1. 先取出存储的字符串字段,做JSON解码得到动态类型结果 final dynamic rawRating = jsonDecode(json['rating'] as String); // 2. 显式转换Map的键值类型,兼容int/double数值格式 rating = Map<String, double>.from( (rawRating as Map).map( (entryKey, entryValue) => MapEntry( entryKey as String, (entryValue as num).toDouble(), ), ), );
- 注意必须加
.toDouble():如果JSON中存储的评分数值为整数(比如5而非5.0),解析后会是int类型,直接强转double会报错,通过num类型做中转可以兼容两种数值格式。
方案2:移除不必要的序列化操作
如果你使用的存储方案(本地KV库、接口请求序列化工具等)本身支持直接存储Map类型对象,不需要手动调用json.encode转字符串:
// 写入时直接存储原Map对象 data['rating'] = this.rating; // 读取时直接做类型转换即可 rating = Map<String, double>.from(json['rating'] as Map);
鲁棒性优化建议
正式环境建议增加类型校验和异常捕获,避免脏数据导致崩溃:
rating = {}; if (json['rating'] != null) { try { dynamic decoded; if (json['rating'] is String) { decoded = jsonDecode(json['rating']); } else if (json['rating'] is Map) { decoded = json['rating']; } if (decoded is Map) { rating = Map<String, double>.from( decoded.map((k, v) => MapEntry(k.toString(), (v as num).toDouble())), ); } } catch (_) { // 解析失败时保留兜底空值,可根据业务需求调整 } }
内容的提问来源于stack exchange,提问作者Yavuz Tarhan
相关产品推荐
相关产品推荐

