Flutter中实现从Firestore仅获取当前登录用户专属联系人数据的问题
我明白你现在遇到的困扰了——你的Flutter app现在会把Firestore里所有用户的联系人都显示出来,想改成只让用户看自己的联系人,但用.where()的时候碰到了类型不匹配的错误。别慌,我来一步步帮你搞定这个问题。
1. 先解决类型不匹配的错误
你碰到的A value of type 'Query<Map<String, dynamic>>' can't be assigned to a variable of type 'CollectionReference<Object?>'错误,原因很直白:FirebaseFirestore.instance.collection('contacts')返回的是CollectionReference类型,而调用.where()之后会返回Query类型,这俩类型不能直接赋值。
解决这个问题有两种实用思路:
思路一:在获取数据流时动态加过滤条件(更推荐)
不用修改contactsCollection的定义,而是在获取contacts流的时候追加.where()过滤逻辑,这样既不会有类型问题,还能保证uid是实例化时传入的有效值。思路二:把变量类型改成Query
如果你想提前定义好带过滤条件的集合引用,可以把contactsCollection的类型改成Query:final Query contactsCollection = FirebaseFirestore.instance.collection('contacts');不过这种方式如果要在初始化时就用
uid过滤,可能会因为uid还没初始化出问题,所以更推荐第一种思路。
2. 正确过滤当前用户的联系人数据
接下来要确保能精准筛选出当前用户的联系人,这里首先得确认你的Firestore数据结构是否合理:
调整数据库结构(关键步骤)
如果你的需求是让每个用户能存储多个联系人,那contacts集合里的每个文档都应该对应一个独立的联系人,而且每个文档必须额外存一个uid字段,用来标记这个联系人属于哪个用户。
举个例子,每个联系人文档的结构应该是这样的:
contacts > [系统生成的随机文档ID] > { name: "张三", phone: "138xxxxxxx", uid: "当前登录用户的UID" }
修改代码实现
第一步:修正添加联系人的方法
你原来的updateUserData方法是用用户的uid作为文档ID来设置数据,这会导致每个用户只能有一个联系人(后续添加会直接覆盖之前的)。我们改成添加新文档的方式,同时把当前用户的uid存入文档:
Future addContact(String name, String phone) async { return await contactsCollection.add({ 'name': name, 'phone': phone, 'uid': uid, // 存入当前用户的UID,方便后续过滤 }); }
第二步:修改联系人数据流,添加过滤条件
修改contacts流的定义,在snapshots()之前加上.where(),只拉取uid等于当前用户uid的文档:
Stream<List<Contacts>> get contacts { return contactsCollection .where('uid', isEqualTo: uid) // 只获取当前用户的联系人数据 .snapshots() .map(_contactsListFromSnapshot); }
3. 特殊情况处理:如果只存用户个人联系方式
如果你的需求不是存储多个联系人,而只是保存当前用户的个人联系方式,那其实不需要用where,直接监听以用户uid为ID的文档就行,修改contacts流为:
Stream<List<Contacts>> get contacts { // 只监听当前用户的专属文档,再包装成列表返回 return contactsCollection.doc(uid).snapshots().map((snapshot) { if (snapshot.exists) { return [Contacts( phone: snapshot.get('phone') ?? '', name: snapshot.get('name') ?? '' )]; } else { return []; } }); }
现在你再运行app,用户应该只能看到自己添加的联系人数据啦!
备注:内容来源于stack exchange,提问作者user23326424

