从动态的Observable数组中将Observables合并为一个Observable吗?

时间:2019-01-15 00:42:38

标签: firebase rxjs google-cloud-firestore rxfire

摘要:本质上,我需要类似from Users where usergroupIds in [1,3,5]的东西。

给出usergroupIds$发出一组ID为[1,3,5]的数组

我想通过userids中的usergroupIds合并所有用户,并合并userIds(不同)

这是我想出的:

usergroupIds$.subscribe(usergroupIds => {
    const users$s = usergroupIds.map(gid => createUsersObservable(gid))
    //  [users$ in group 1, users$ in group 3, users$ in group 5]
    const users$ = combineLatest(...user$s).pipe(
        distinct(user => user.id)
    )
})

createUsersObservable = gid => 
  collectionData(db.collection('users').where('groupId', '==', gid)) // rxFire firestore

每次更改都退订并重新订阅users$似乎是错误的?

是否可以在RxJS中完全表达users$,而不必每次都在预订中创建它?

更新: 在@FanCheung的帮助下:

combinedUsers$ = userGroupIds$.pipe(
        switchMap(userGroupIds => {
            const users$s = userGroupIds.map(groupId =>
                createUsersObservable(groupId))
            return combineLatest(...users$s)
        })

但是,由于usersObservable一次发出一个用户数组,所以CombineUsers $会产生类似[[userA, userB], [userB, userC], [userA, userD]]之类的东西,我不介意在subscription上执行额外的处理:

combinedUsers$.subscribe(combinedUsers => {
        const userMap = {}
        for (const users of combinedUsers) 
            users.forEach(user => (userMap[user.id] = user))
        const uniqueUsers = Object.values(userMap)

        // update UI to uniqueUsers
    })

但是,有没有办法使用某种方式将combinedUsers$的结果展平,然后执行distinct运算符?

2 个答案:

答案 0 :(得分:1)

看看是否可行。基本上,它会在usergroupIds $发出时触发,因此您可以观察到新的动态。如果您始终希望源可观察的shareReplay在订阅时发出最后保存的值,则需要usergroupdIds$

usergroupIds$.pipe(
shareReplay(1),
switchMap(usergroupIds => {
    const users$Array = usergroupIds.map(gid => createUsersObservable(gid))
    //  [users$ in group 1, users$ in group 3, users$ in group 5]
   return forkJoin(...users$Array).pipe(
        map(arr=>[].concat(...arr)),
        switchMap(arr=>from(arr)),
        distinct(user => user.id)
    )
})
)

答案 1 :(得分:0)

因此,您不想每次createUsersObservable发出时都单独向usergroupIds$发出请求。听起来mergeScan是一个很好的用例:

usergroupIds$.pipe(
  mergeScan((users, user) => createUsersObservable().pipe(
    map(user => [user, ...users]),
  ), []),
);

实时演示:https://stackblitz.com/edit/rxjs-8zybdu