如何访问Firestore子集合并将其作为Observable返回?
问题描述
手动添加collectionRef时能访问子集合,但在构造函数外使用CollectionReference时,报错“Property 'collectionRef' does not exist on type 'UnitlogService'”。想要用getTasks(id)传入的动态ID替代手动固定的ID,目前考虑两种方向:在构造函数前获取ID,或者找到构造函数外使用CollectionReference的方法,同时希望得到AngularFire子集合的相关帮助或参考文档。
服务文件代码如下:
import { collection, CollectionReference, Firestore }from'@angular/fire/firestore'; export class UnitlogService { private collectionRef: CollectionReference; constructor( private firestore: Firestore, private auth: Auth, private storage: Storage ) { // const id inserted manually // would like to use id form getTasks(id) which connects the page with this service const id = 'LvuYX0jreCB1sL5IORCM' this.collectionRef = collection(this.firestore, `tasks/${id}/unit-logs-sub-collection`); onAuthStateChanged(this.auth, (user) => { if (user) { const tasksQuery = query( this.collectionRef); const collectionSub = collectionData(tasksQuery, { idField: 'id', }) as Observable<Task[]>; this.tasksSub = collectionSub.subscribe((tasks) => { this.tasks.next(tasks); }); } else { this.tasks.next([]); this.tasks.unsubscribe(); } }); } getTasks(id: any) { console.log("id",id) return this.tasks.asObservable() }
解决方案
方案1:动态生成集合引用并返回数据流
不需要把collectionRef作为类属性保存,直接在getTasks方法里根据传入的ID创建子集合引用,结合用户认证状态返回数据流:
import { collection, Firestore, query, collectionData } from '@angular/fire/firestore'; import { Auth, onAuthStateChanged } from '@angular/fire/auth'; import { Observable } from 'rxjs'; export class UnitlogService { constructor(private firestore: Firestore, private auth: Auth) {} getTasks(id: string): Observable<Task[]> { return new Observable((observer) => { // 监听用户认证状态 const authUnsubscribe = onAuthStateChanged(this.auth, (user) => { if (user) { // 动态创建子集合引用 const collectionRef = collection(this.firestore, `tasks/${id}/unit-logs-sub-collection`); const tasksQuery = query(collectionRef); const dataSub = collectionData(tasksQuery, { idField: 'id' }) as Observable<Task[]>; // 订阅数据并传递给观察者 const sub = dataSub.subscribe({ next: tasks => observer.next(tasks), error: err => observer.error(err) }); return () => sub.unsubscribe(); } else { observer.next([]); } }); // 清理认证监听 return () => authUnsubscribe(); }); } }
方案2:类内动态更新集合引用并复用订阅逻辑
如果需要复用集合引用和订阅逻辑,可以在getTasks中更新类属性,同时重新绑定数据流:
import { collection, CollectionReference, Firestore, query, collectionData } from '@angular/fire/firestore'; import { Auth, onAuthStateChanged } from '@angular/fire/auth'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; export class UnitlogService { private collectionRef?: CollectionReference; private tasks = new BehaviorSubject<Task[]>([]); private tasksSub?: Subscription; private authSub?: Subscription; constructor(private firestore: Firestore, private auth: Auth) { // 初始化认证状态监听 this.authSub = onAuthStateChanged(this.auth, (user) => { if (!user) { this.tasks.next([]); this.tasksSub?.unsubscribe(); } else { this.collectionRef && this.subscribeToCollection(); } }); } // 封装订阅集合的逻辑 private subscribeToCollection() { if (!this.collectionRef) return; this.tasksSub?.unsubscribe(); const tasksQuery = query(this.collectionRef); const dataSub = collectionData(tasksQuery, { idField: 'id' }) as Observable<Task[]>; this.tasksSub = dataSub.subscribe(tasks => this.tasks.next(tasks)); } getTasks(id: string): Observable<Task[]> { // 更新子集合引用 this.collectionRef = collection(this.firestore, `tasks/${id}/unit-logs-sub-collection`); // 若用户已登录,立即订阅新集合 onAuthStateChanged(this.auth, user => user && this.subscribeToCollection()); return this.tasks.asObservable(); } // 清理所有订阅,可在组件销毁时调用 cleanup() { this.tasksSub?.unsubscribe(); this.authSub?.unsubscribe(); this.tasks.complete(); } }
核心说明
- 构造函数只初始化依赖注入服务:动态参数(如页面传入的ID)不要放在构造函数中处理,应在对应方法内接收并使用。
- 严格管理订阅生命周期:所有订阅必须手动清理,避免内存泄漏,可通过服务的清理方法或组件内的
takeUntil操作符实现。 - AngularFire子集合基础用法:通过
collection(firestore, '父集合/父文档ID/子集合名称')创建子集合引用,后续的collectionData、query等操作与普通集合完全一致。
内容的提问来源于stack exchange,提问作者Thomas Degroot
相关产品推荐
相关产品推荐

