Flutter更新Firebase依赖后报DocumentSnapshotPlatform字段不存在错误如何解决
问题原因
该报错是cloud_firestore 2.0及以上版本的官方不兼容更新:旧版本中DocumentSnapshot的[]运算符读取不存在的字段会返回null,2.0之后调整为直接抛出Bad state: cannot get a field on a DocumentSnapshotPlatform which does not exist异常,目的是提前暴露字段不存在的问题,但对无预定义字段的集合非常不友好。
解决方案
按改动量从小到大排序,可根据自己的项目情况选择:
方案1:修改Stream构造逻辑(改动最小,仅改1处)
如果你的Stream是统一构建的,直接在获取快照前用withConverter把文档自动转成Map,后续读取字段的代码完全不用修改,和旧版本行为完全一致:
// 你原来构造stream的代码类似如下 // final stream = FirebaseFirestore.instance.collection('你的集合名').snapshots(); // 只需要增加withConverter配置即可 final stream = FirebaseFirestore.instance .collection('你的集合名') .withConverter<Map<String, dynamic>>( fromFirestore: (snapshot, _) => snapshot.data() ?? {}, toFirestore: (map, _) => map, ) .snapshots();
改完之后,你原有代码中priceDetail[index]['字段名']的写法不需要做任何调整,不存在的字段会自动返回null。
方案2:单页面局部修改(适合仅少数页面读取无预定义字段集合)
如果不想改动全局的Stream构造,只需要在当前页面读取文档时先调用data()转成Map即可:
// 原有代码不变 var priceDetail = queryDetailSnapShot.data.docs; return ListView.builder( reverse: false, itemCount: priceDetail.length, itemBuilder: (ctx, index) { // 新增这一行,把文档数据转成Map,不存在的键默认返回null final docMap = priceDetail[index].data() as Map<String, dynamic>? ?? {}; if (_selectedBottomIndex == 1) { return CostExpenseRequestContainer( widget.storenameUser, widget.storeCostAcess, widget.userName, widget.userEmail, widget.userId, widget.userLanguage, // 把priceDetail[index]['Storename']替换为docMap['Storename']即可 docMap['Storename'], docMap['Created_dt'], docMap['Expense_type_en'], docMap['Expense_type_th'], docMap['Expense_amount_org'], docMap['Expense_amount_approved'], docMap['Visible_to'], docMap['Expense_status'], docMap['Photo_url'], docMap['Service_dt'], docMap['Partner_account_number'], docMap['Partner_value_th'], docMap['Partner_value_en'], // 文档id还是用原有写法 priceDetail[index].id, key: ValueKey(priceDetail[index].id,), ); } else { // 另一个分支的字段同理替换即可 return CostExpenseTrContainer( // ...其余参数替换逻辑一致 ); } } );
用编辑器的全局替换功能,把当前页面的priceDetail[index]['批量替换为docMap[',1分钟即可完成修改。
方案3:全局扩展方法(适合多页面都有同类需求)
给DocumentSnapshot写个全局扩展方法,所有页面都可以调用,不用重复写转Map的逻辑,还支持设置默认值:
// 放在项目全局公共工具文件中 extension DocumentSnapshotExt on DocumentSnapshot { T? get<T>(String key, [T? defaultValue]) { final data = this.data() as Map<String, dynamic>?; final value = data?[key]; if (value is T) return value; return defaultValue; } } // 调用的时候把原来的写法替换即可 // 原有写法:priceDetail[index]['Storename'] // 新写法: priceDetail[index].get<String>('Storename') // 也可以设置默认值,比如字段不存在返回空字符串 priceDetail[index].get<String>('Expense_type_en', '')
内容的提问来源于stack exchange,提问作者Simeon Angelov
相关产品推荐
相关产品推荐

