1

我正在StencilJS使用 Google Firestore 后端创建一个应用程序(无框架),并且我想尽可能地使用RxFireRxJS库来简化数据访问代码。如何将来自使用参考 ID 的两个不同集合的数据组合成一个可观察的流数据?

我已经阅读并尝试了几个在线示例,每个示例都使用具有不同嵌套复杂性级别的运算符的不同组合。https://www.learnrxjs.io/似乎是一个很好的资源,但它没有提供对我有意义的业务线示例。这个问题非常相似,也许唯一的区别是使用 RxFire 的一些翻译?还在看那个。只是为了比较,在 SQL 中,这将是一个SELECT带有INNER JOIN引用 ID 的语句。

具体来说,我有一个集合Games

{ id: "abc000001", name: "Billiards" },
{ id: "abc000002", name: "Croquet" },
...

和一个集合Game Sessions

{ id: "xyz000001", userId: "usr000001", gameId: "abc000001", duration: 30 },
{ id: "xyz000002", userId: "usr000001", gameId: "abc000001", duration: 45 },
{ id: "xyz000003", userId: "usr000001", gameId: "abc000002", duration: 55 },
...

我想观察一个合并集合Game SessionswheregameId本质上是替换为Game.name.

我目前有game-sessions-service.ts一个功能来获取特定用户的会话:

import { collectionData } from 'rxfire/firestore';
import { Observable } from 'rxjs';
import { GameSession } from '../interfaces';

observeUserGameSesssions(userId: string): Observable<GameSession[]> {

    let collectionRef = this.db.collection('game-sessions');
    let query = collectionRef.where('userId', '==', userId);

    return collectionData(query, 'id);
}

而且我已经尝试过使用pipeand的各种变化mergeMap,但我不明白如何使它们正确地组合在一起。我想建立一个接口GameSessionView来表示合并的数据:

export interface GameSessionView {
    id: string,
    userId: string,
    gameName: string,
    duration: number
}

observeUserGameSessionViews(userId: string): Observable<GameSessionView> {

    this.observeUserGameSessions(userId)
    .pipe(
        mergeMap(sessions => {
            // What do I do here? Iterate over sessions 
            // and embed other observables for each document?
        }
    )
}

可能,我只是停留在一种标准化的思维方式中,所以我愿意接受有关管理数据的更好方法的建议。我只是不想有太多的重复来保持同步。

4

1 回答 1

0

您可以使用以下代码(也可用作Stackblitz):

const games: Game[] = [...];
const gameSessions: GameSession[] = [...];

combineLatest(
  of(games),
  of(gameSessions)
).pipe(
  switchMap(results => {
    const [gamesRes, gameSessionsRes] = results;
    const gameSessionViews: GameSessionView[] = gameSessionsRes.map(gameSession => ({
      id: gameSession.id,
      userId: gameSession.userId,
      gameName: gamesRes.find(game => game.id === gameSession.gameId).name,
      duration: gameSession.duration
    }));
    return of(gameSessionViews);
  })
).subscribe(mergedData => console.log(mergedData));

说明:
您可以 结合combineLatest来自多个 Obervables 的最新值。如果您有“多个(..)相互依赖以进行某些计算或确定的可观察对象” ,则可以使用它。
因此,假设您的Games 和GameSessions 列表是 Observables,您可以组合每个列表的值。
在 中,您通过迭代sswitchMap创建新的类型对象,使用属性,并在s的第二个列表中找到值。请注意,此示例中没有错误处理。 正如您返回另一个 Observable 所期望的那样,合并后的列表将返回.GameSessionViewGameSessioniduserIddurationgameNameGamegameId
switchMapof(gameSessionViews)
最后,你可以subscribe到这个过程中看到预期的结果。

当然,这不是您可以做到的唯一方法,但我发现它是最简单的一种。

于 2019-05-19T14:24:48.247 回答