首页 > 解决方案 > 没有为“对象”类型定义“文档”

问题描述

当我输入此代码时:

buildSearchRes() {
  return FutureBuilder(
    future: searchResultsFuture,
    builder: (context, snapshot) {
      if (!snapshot.hasData) {
        return cargandoCircular();
      }

      List<UserRes> searchRes = [];
      snapshot.data!.docs.forEach((doc) {
        User user = User.fromDocument(doc);
        UserRes searchRes = UserRes(user);
        searchRes.add(searchRes);
      });
      return ListView(
        children: searchRes,
      );
    },
  );
}

我得到错误:

The getter 'docs' isn't defined for the type 'Object'.
Try importing the library that defines 'docs', correcting the name to the name of an existing getter, or defining a getter or field named 'docs'.

我已经在导入cloud_firestore包了。

我曾经得到一个“'docs'不能无条件访问,因为接收者可以为空”错误,但添加一个空检查解决了它。

这是代码的其余部分以及其他相关部分

class _BuscarPerfilState extends State<BuscarPerfil> {
 TextEditingController searchController = TextEditingController();
 late Future<QuerySnapshot>? searchResultsFuture;

handleSearch(String query) {
 Future<QuerySnapshot> users = usersRef
  .where("displayName", isGreaterThanOrEqualTo: query)
  .get(); //getDocuments();
 setState(() {
  searchResultsFuture = users;
 });}

AppBar buildSearchField() {
return AppBar(
  backgroundColor: Colors.white,
  title: TextFormField(
    controller: searchController,
    decoration: InputDecoration(
      hintText: "Buscar un usuario...",
      filled: true,
      prefixIcon: Icon(
        Icons.account_box,
        size: 28.0,
      ),
      suffixIcon: IconButton(
        icon: Icon(Icons.clear),
        onPressed: clearSearch,
      ),
    ),
    onFieldSubmitted: handleSearch,
  ),
);}



buildSearchResults() {
return FutureBuilder(
  future: searchResultsFuture,
  builder: (context, snapshot) {
    if (!snapshot.hasData) {
      return cargandoCircular(); 
    }

    List<UserResult> searchResults = [];
    snapshot.data!.docs.forEach((doc) {
      User user = User.fromDocument(doc);
      UserResult searchResult = UserResult(user);
      searchResults.add(searchResult);
    });
    return ListView(
      children: searchResults,
    );
  },
);}

@override
Widget build(context) {
return Scaffold(
  backgroundColor: Theme.of(context).primaryColor.withOpacity(0.2),
  appBar: buildSearchField(),
  body:
      searchResultsFuture == null ? buildNoContent() : buildSearchResults(),
);}}

为了对用户数据进行建模,我在另一个 .dart 文档上做了这个并导入了它:

class User {
final String id;
final String username;
final String email;
final String photoUrl;
final String displayName;
final String bio;

User(
  {required this.id,
  required this.username,
  required this.email,
  required this.photoUrl,
  required this.displayName,
  required this.bio});

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'],
);}}

标签: flutterdartgoogle-cloud-firestore

解决方案


我认为您需要查看更多 firebase 示例并检查使用的函数、返回类型和对象。

我将尝试简要介绍您可以进行的更改:

使用FutureBuilder(或StreamBuilder)很好。更好的是使用dart 泛型

例如FutureBuilder<User>(...)

执行 Firestore 查询时,您必须知道您得到了什么。你得到的是QuerySnapshot还是DocumentSnapshot

使用 a ,您将从查询的 Firestore集合QuerySnapshot中获得一堆文档,您可以在其中获取 a of ( example ) 或获取最新的 using ( example )。Stream.snapshots().get()

这样做会为您提供QuerySnapshot<Map<String, dynamic>>具有docs吸气剂的 a,您可以.map()将其用于另一种类型或您选择的对象(参见示例),您将在 a 中使用它ListView或稍后对其进行处理。


以你的例子,我会建议类似的东西:

class FirestoreService {
  final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;

  Future<List<User>> searchUsersByDisplayName(String displayName) {
    const usersRef = _firebaseFirestore.collections(...);
    return usersRef.where("displayName", isGreaterThanOrEqualTo: query).get().then((value) => value.docs.map(User.fromDocument).toList());
  }
}

将您的查询与您的视图分开,否则它会变得混乱,并且您会遇到一堆问题。

接下来,您的小部件状态,使用后期或空安全,而不是两者:

class _BuscarPerfilState extends State<BuscarPerfil> {
  TextEditingController searchController = TextEditingController();
  Future<List<User>>? searchResultsFuture;
  //...

最后,用户 aFutureBuilder<List<User>>检索您的数据并显示它,例如(未经测试)

@override
Widget build(context) {
  FirestoreService _firestoreService = FirestoreService();
  return Scaffold(
    backgroundColor: Theme
        .of(context)
        .primaryColor
        .withOpacity(0.2),
    appBar: buildSearchField(),
    body: FutureBuilder<List<User>>(    // user futurebuilder or streambuilder
      builder: (context, snapshot) {
        // always check for errors
        if (!snapshot.hasError) { 
          return Text("Error retrieving results");
        }
      
        // depending on the connection state, you want to show different UI updates
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
          // we are waiting on a connection, etc
            return CircularProgressIndicator();
          case ConnectionState.active:
          case ConnectionState.done:
          // we are grabbing data, this *can* continue on for a few seconds or we are done
          // display results as you wish
            return ListView.separated(
                itemBuilder: (context, index) {
                  User user = snapshot.data[index];
                  return ListTile(
                    title: Text(user.displayName),
                    leading: CircleAvatar(
                      foregroundImage: Image
                          .network(user.photoUrl)
                          .image,
                    ),
                    subtitle: Text(user.email),
                    onTap: () {
                      // go to profile page
                    },
                  )
                },
                separatorBuilder: (context, index) => Divider(),
                itemCount: snapshot.data.length);
        }
      },
      future: _firestoreService
          .searchUsersByDisplayName("query value here") // your Future query
      initialData: [], // empty data to begin with
    ),
  );
}

推荐阅读