Flutter:未处理的异常:坏状态:DocumentSnapshotPlatform中不存在该字段

32

我是Flutter的新手,正在通过教程构建社交媒体应用程序,现在正在进行自定义。 现在我尝试向用户个人资料页面添加更多输入字段,然后开始出现以下错误。 当我可以登录时,我的时间线页面变成了带有警告的红色:Bad state: field does not exist within the DocumentSnapshotPlatform

我运行了Flutter clean,现在我的用户无法登录应用程序

我遇到了这个错误:

E/flutter ( 3971): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Bad state: field does not exist within the DocumentSnapshotPlatform
E/flutter ( 3971): #0      DocumentSnapshotPlatform.get._findKeyValueInMap
package:cloud_firestore_platform_interface/…/platform_interface/platform_interface_document_snapshot.dart:82
E/flutter ( 3971): #1      DocumentSnapshotPlatform.get._findComponent
package:cloud_firestore_platform_interface/…/platform_interface/platform_interface_document_snapshot.dart:98
E/flutter ( 3971): #2      DocumentSnapshotPlatform.get
package:cloud_firestore_platform_interface/…/platform_interface/platform_interface_document_snapshot.dart:113
E/flutter ( 3971): #3      DocumentSnapshot.get
package:cloud_firestore/src/document_snapshot.dart:49
E/flutter ( 3971): #4      DocumentSnapshot.[]
package:cloud_firestore/src/document_snapshot.dart:56
E/flutter ( 3971): #5      new User.fromDocument
package:findemed/models/user.dart:46
E/flutter ( 3971): #6      _HomeState.createUserInFirestore
package:findemed/pages/home.dart:152
E/flutter ( 3971): <asynchronous suspension>
E/flutter ( 3971): #7      _HomeState.handleSignIn
package:findemed/pages/home.dart:60
E/flutter ( 3971): #8      _HomeState.initState.<anonymous closure>
package:findemed/pages/home.dart:46
E/flutter ( 3971): #9      _rootRunUnary (dart:async/zone.dart:1198:47)

初始指向我主页文件中的这个箭头部分。

buildUsersToFollow() {
  return StreamBuilder(
    stream: usersRef.orderBy('timestamp', descending: true)
    .limit(0)
    .snapshots(),
    builder: (context, snapshot) {
      if (!snapshot.hasData) {
        return circularProgress(context);
      }
      List<UserResult> userResults = [];
      snapshot.data.docs.forEach((doc) {
        User user = User.fromDocument(doc);
        final bool isAuthUser = currentUser.id == user.id;
        final bool isFollowingUser = followingList.contains(user.id);
        // remove auth user from recommended list
        if (isAuthUser) {
          return;
        } else if (isFollowingUser) {
          return;
        } else {
          UserResult userResult = UserResult(user);
          userResults.add(userResult);
        }
        });


现在它指向这段代码:

factory User.fromDocument(DocumentSnapshot doc) {
    return User(
      id: doc['id'],
      email: doc['email'],
      username: doc['username'],
      photoUrl: doc['photoUrl'],
      displayName: doc['displayName'],
      bio: doc['bio'],      
      fullNames: doc['fullNames'],
      practice: doc['practice'],
      speciality: doc['speciality'],
      phone: doc['phone'],
      mobile: doc['mobile'],
      emergency: doc['emergency'],
      address: doc['address'],
      city: doc['city'],
      location: doc['location'],
    );
  }

这是堆栈中指出的另一段代码。
currentUser = User.fromDocument(doc);
    print(currentUser);
    print(currentUser.username);

1
请编辑问题以指示此错误所涉及的代码行,并清楚地说明您希望此代码实现的功能(特别是考虑到您请求了0个文档的限制)。 - Doug Stevenson
29个回答

58

对于最新版本的cloud_firestore (2.4.0或更高版本),我终于找到了解决方法:

对于旧版的cloud_firestore,只需在末尾添加??以避免空值即可解决问题:

factory User.fromDocument(DocumentSnapshot doc) {
   return User(
      id: doc.data()['id'] ?? '',
   );
}

但在新版本中这是不可能的,因为会返回错误状态

factory User.fromDocument(DocumentSnapshot doc) {
   return User(
       id: doc.get('id')
   );
}

只需检查文档是否包含关键字即可解决该问题:

factory User.fromDocument(DocumentSnapshot doc) {
   return User(
      id: doc.data().toString().contains('id') ? doc.get('id') : '', //String
      amount: doc.data().toString().contains('amount') ? doc.get('amount') : 0,//Number
      enable: doc.data().toString().contains('enable') ? doc.get('enable') : false,//Boolean
      tags: doc.data().toString().contains('tags') ? doc.get('tags').entries.map((e) => TagModel(name: e.key, value: e.value)).toList() : [],//List<dynamic>
   );
}

希望这能对您有所帮助,祝好!:)


4
这应该是最新Firestore的最终答案。 - C.K.
1
对于布尔值,请使用 id: doc.get('id') - Maruf Hassan
1
感谢您的评论,为了避免混淆,我已经更新了答案,祝好。 - silexcorp
1
在尝试打印一个值一个小时后,这个帮了我一把哈哈,谢谢。 - ammu
1
这不可能是答案。如果'id'不是键而是值,会怎样?这将会生成错误。 - M4trix Dev
显示剩余3条评论

27

将您的工厂更改为以下内容:

factory User.fromDocument(DocumentSnapshot doc) {
  return User(
    id: doc.data()['id'],
    email: doc.data()['email'],
    username: doc.data()['username'],
    photoUrl: doc.data()['photoUrl'],
    displayName: doc.data()['displayName'],
    bio: doc.data()['bio'],      
    fullNames: doc.data()['fullNames'],
    practice: doc.data()['practice'],
    speciality: doc.data()['speciality'],
    phone: doc.data()['phone'],
    mobile: doc.data()['mobile'],
    emergency: doc.data()['emergency'],
    address: doc.data()['address'],
    city: doc.data()['city'],
    location: doc.data()['location'],
  );
}

1
更改为 doc.data() 解决了一个问题,然后我不得不通过将 .limit(0) 改为正整数来解决它,并且它可以运行。 - Ace
9
我尝试过这样做,但出现了“运算符'[]'未定义于类型'Object'”的错误提示。 - s3v3ns
1
@s3v3ns你可以使用这个解决方法来避免该错误:(e.data() as dynamic)['field']。不太美观,但是可以解决问题。或者创建一个动态别名final _snapshot = snapshot as dynamic;。也许有更好的方式,我还在学习中。 - Adrian Moisa
谢谢Adrian,非常有用的解决方法。为什么将其转换为动态类型会起作用,有解释吗?当我遇到@s3v3ns提到的错误时,我正在使用context.watch<DocumentSnapshot>().data() - Petar Bivolarski

19

我有同样的问题,我通过询问参数是否存在来解决了它。

以下是我的先前代码:

if(widget.document['imageUrl'] == null)//here was my error, I was calling a field that did not exist in the document
  Container(
    child:Icon(
      Icons.image,
      size: 20.0,
      color: Colors.grey,
    ),
  ),

这是我的工作方式:

if(widget.document.data().containsKey('imageUrl'))
  Container(
    child:Icon(
      Icons.image,
      size: 20.0,
      color: Colors.grey,
    ),
  ),

7

当使用生成器方法显示文档数据时,如果传递了不存在于文档中的属性名称,则也可能发生此问题。这对我来说解决了问题。


1
谢谢兄弟。使用Firebase时,只需将doc['id']替换为doc.get('id')即可。 - M E S A B O

3
简单的解决方案是使用来自DocumentSnapshot的data()方法,并将其转换为Map,最后你可以根据给定代码片段所示检查Map中是否存在key。
fireStore.collection('transactions').get().then((QuerySnapshot querySnapshot) {
  List<TransactionModel> transactions = [];
  querySnapshot.docs.forEach((DocumentSnapshot doc) {
    transactions.add(TransactionModel.fromJson(doc.data() as Map<String,dynamic>));
  });
  onResponse(FireStoreApiResponse.withSuccess(transactions));
}).catchError((onError) {
  onResponse(FireStoreApiResponse.withError(onError));
});

在TransactionModel类中
TransactionModel.fromJson(Map<String, dynamic> json) {
date = json['date'];
memberId = json['member_id'];
if (json.containsKey("member_contact")) memberContact = json['member_contact'];
if (json.containsKey("member_name")) memberName = json['member_name'];
packageId = json['package_id'];
grossAmount = json['gross_amount'];
discount = json['discount'];
netAmount = json['net_amount']; }

3
实现DocumentSnapshot类型的扩展方法。
2022年,对我来说最简单的解决方案是实现DocumentSnapshot类型的扩展方法。这可以设置为完全覆盖get方法(此处不提供示例),或者实现更强类型数据的自定义方法(如下所示)。
方法的核心功能应遵循此答案中指出的模式。如果您在一个单独的文件中创建此扩展并导入它,还需要导入cloud_firestore依赖项到该文件中以访问DocumentSnapshot类型。
在此示例中,新方法直接在快照上可用。
extension CustomGetters on DocumentSnapshot {
  int getInt(key) {
    return this.data().toString().contains(key) ? this.get(key) : 0;
  }
  String getString(key) {
    return this.data().toString().contains(key) ? this.get(key) : '';
  }
}

要访问,请调用自定义方法而不是通常的获取方法:

/**...fetch the snap...then...**/
snap.getInt('id');
snap.getString('username');

3

只有当您在Flutter代码中输入区分大小写的字段名称或存在于Firestore集合字段中的字段名称时,才会出现错误(坏状态:文档中不存在该字段)。

请记住,字段名称区分大小写,因此您必须使用与Firestore集合字段中提到的相同字段。

例如:您的Firebase Firestore集合字段包含“用户名”字段,而您在Flutter代码中使用了“username”,则会出现此错误。因此,要修复此错误,请使用与Firestore中提到的相同字段名。

Cloud FireStore集合字段包括“UserName”等,因此您必须在Flutter代码中完全使用相同的内容。 查看Cloud FireStore集合字段

由于大小写敏感性,这是正确的,因为Firestore集合中的字段为("UserName"),在Flutter代码中使用了("UserName")。

用于Flutter代码的正确字段名称 由于大小写敏感性,这是错误的,因为Firestore集合中的字段为("UserName"),而在Flutter代码中使用了("username") 用于Flutter代码的错误字段名称

如果需要更多帮助,请联系我......祝编码愉快!


2
一个更好更简单的方式
factory User.fromDocument(DocumentSnapshot snap) {

   var doc = snap.data();
   id: doc['id'],
   email: doc['email'],
   ......
   ......
      
}

2

当任何参数键与firebase声明的字段不匹配或有拼写错误时,就会出现此错误。

例如:在firebase文档中,我们有一个键/值为“username”的参数。

username: "Ali Murtaza"

现在,如果我们在模型内部错过了它或写成这样:
username: doc["usernameeeeee"] as String

接下来,将会发生一个异常:“状态不良:字段不存在”。

为了处理这种情况,我们需要检查我们获取的文档是否包含特定的字段。检查方法如下:

username: doc.data()!.containsKey("username")
              ? doc["username"] as String
              : "Username Key Does Not Exist inside Firebase Document",

2

我遇到了同样的问题。后来发现这是因为Firestore中的键名末尾有一个空格。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接