带动态路径的Firestore CollectionReference无法工作求助
解决Firestore动态路径查询失败的问题
我来帮你排查下这个问题的核心原因,其实是变量初始化时机不匹配导致的!
问题根源
你把addressCollection作为类的成员变量直接声明并初始化了,这部分代码会在FirestoreDatabase类实例化的瞬间就执行。但此时userId还是null——因为你是之后调用setUserId方法才给它赋值的,所以实际生成的路径是users/null/addresses,这当然查不到任何数据。
而硬编码路径能正常运行,是因为它直接用了固定的字符串,不存在变量未初始化的问题。
三种可行的解决方案
方案1:将集合引用改为Getter方法
每次访问addressCollection时才动态生成路径,确保使用的是最新的userId:
class FirestoreDatabase { final _service = FirestoreService.instance; static String userId; void setUserId(uid) { userId = uid; } // 改成Getter方法,每次调用都会重新生成路径 CollectionReference get addressCollection { return Firestore.instance.collection('users/$userId/addresses'); } Stream<List<Address>> get addressesStream { return addressCollection.snapshots().map(_addressListFromSnapshot); } List<Address> _addressListFromSnapshot(QuerySnapshot snapshot) { return snapshot.documents.map((doc) { return Address.fromMap(doc.data); }).toList(); } }
方案2:在setUserId方法中初始化集合引用
先声明addressCollection,等到设置userId时再完成初始化:
class FirestoreDatabase { final _service = FirestoreService.instance; static String userId; CollectionReference addressCollection; // 先声明,不初始化 void setUserId(uid) { userId = uid; // 在这里用已赋值的userId初始化集合 addressCollection = Firestore.instance.collection('users/$userId/addresses'); } Stream<List<Address>> get addressesStream { // 加个断言,防止未设置userId就调用stream assert(addressCollection != null, "请先调用setUserId设置用户ID"); return addressCollection.snapshots().map(_addressListFromSnapshot); } List<Address> _addressListFromSnapshot(QuerySnapshot snapshot) { return snapshot.documents.map((doc) { return Address.fromMap(doc.data); }).toList(); } }
⚠️ 注意:这种方式必须先调用setUserId,再使用addressesStream,否则会抛出空指针异常。
方案3:将userId作为构造函数参数(推荐)
这是最优雅且安全的方式,通过构造函数强制传入userId,保证实例化时userId已经存在,从根源避免未初始化问题:
class FirestoreDatabase { final _service = FirestoreService.instance; final String userId; final CollectionReference addressCollection; // 构造函数初始化时直接生成集合引用 FirestoreDatabase(this.userId) : addressCollection = Firestore.instance.collection('users/$userId/addresses'); Stream<List<Address>> get addressesStream { return addressCollection.snapshots().map(_addressListFromSnapshot); } List<Address> _addressListFromSnapshot(QuerySnapshot snapshot) { return snapshot.documents.map((doc) { return Address.fromMap(doc.data); }).toList(); } }
使用时直接传入userId实例化:
final db = FirestoreDatabase("r9qClctByGXinYAmB2MqQNctgd53");
这种方式不需要静态变量,每个FirestoreDatabase实例对应一个用户,更符合面向对象设计,也避免了静态变量可能带来的并发问题。
内容的提问来源于stack exchange,提问作者Keek
相关产品推荐
相关产品推荐

