You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:54:18