【问题标题】:Chaining Angular Firestore Collections链接 Angular Firestore 集合
【发布时间】:2026-02-12 19:00:02
【问题描述】:

这很难解释,但我会尽力而为。我在 Firebase 中有这样的数据库结构设置:

用户(Firebase 用户)

  • 电子邮件

连接

  • 电子邮件
  • 角色

用户详情

  • 电子邮件
  • 名字
  • 姓氏
  • 地址

基本上我要做的是使用 AngularFireAuth 获取当前用户,然后通过 user.email 查询 User Details 集合,然后通过 user.email 查询 Connections 集合。最后,将所有这些映射到一个 User 模型并将其存储在一个 observable 中。

编辑:

我已经弄清楚如何将第一个集合提供给用户 observable,但不知道从这里去哪里。

    this.user = this.afAuth.authState.pipe(
        map(user => user.email),
        flatMap(email => this.afs.collection<User>(this.userRef, res => res.where('email', '==', email)).valueChanges()),
        mergeAll(),
        first()
    )

编辑2:

所以这就是我想出的,它正在工作,但它似乎不正确。我可以看出这会对性能产生影响(尽管影响不大)。可能永远不会将其用于生产,但我会继续使用此解决方案作为概念证明,直到找到更好的方法。

    this.user = this.afAuth.authState.pipe(
        map(user => user.email),
        concatMap(email => {
            return zip(
                this.afs.collection<Connection>('connections', res => res.where('email', '==', email)).snapshotChanges().pipe(mergeAll(), first()), 
                this.afs.collection<User>('users', res => res.where('email', '==', email)).snapshotChanges().pipe(mergeAll(), first())
            )
        }),
        map(([connection, details]) => {
            const a = connection.payload.doc.data() as Connection;
            const b = details.payload.doc.data() as User;
            return { ...a, ...b };
        })
    ) 

【问题讨论】:

    标签: angular firebase rxjs google-cloud-firestore angularfire2


    【解决方案1】:

    我最初的方法是为用户详细信息和连接创建 2 个单独的 observable,然后使用 combineLatest 获取完整的用户配置文件:

    import { combineLatest } from 'rxjs';
    
    let connectionCollection$: Observable<DocumentChangeAction<T>[]>
    let userDetailsCollection$: Observable<DocumentChangeAction<T>[]>
    let user: UserModel;
    
    
    this.afAuth.authState.pipe(
            map(user => user.email),
            tap(email => {
                this.connectionCollection$ = this.afs.collection('connection', res => res.where('email', '==', email)).snapshotChanges()
                this.userDetailsCollection$ = this.afs.collection('userdetails', res => res.where('email', '==', email)).snapshotChanges() 
            }
    )
    
    combineLatest(connectionCollection$, userDetailsCollection$).subscribe(
        ([connection, userDetails]) => {
            //map the result to the user object e.g user.grandma = connection.grandma
        }
    )
    
    

    更多使用 combineLatest 的例子:

    Learn Rxjs

    【讨论】:

    • 我已经完全按照您的建议进行了尝试,但我无法使其成功运行。 connectionCollection$ 和 userDetailsCollection$ observables 仍未定义,这真的很奇怪。
    • 嗯,我将首先通过注销用户来测试 authState 管道是否正在发射。然后检查数据库是否有任何有效的电子邮件连接到该用户
    • 您也可以为此使用forkJoin。 forkJoin 只会在所有可观察对象都产生至少一个值时发出值
    【解决方案2】:

    所以经过一番研究,我想出了这个可行的解决方案。可能不是最好的方法,但对于概念验证项目,我可以接受。

    this.user = this.afAuth.authState.pipe(
        map(user => user.email),
        concatMap(email => {
            return zip(
                this.afs.collection<Connection>('connections', res => res.where('email', '==', email)).snapshotChanges().pipe(mergeAll(), first()), 
                this.afs.collection<User>('users', res => res.where('email', '==', email)).snapshotChanges().pipe(mergeAll(), first())
            )
        }),
        map(([connection, details]) => {
            const a = connection.payload.doc.data() as Connection;
            const b = details.payload.doc.data() as User;
            return { ...a, ...b };
        })
    ) 
    

    【讨论】: