我正在使用Google Firestore后端创建一个StencilJS
应用(无框架),并且我想尽可能地使用RxFire
和RxJS
库来简化数据访问码。如何将来自两个使用引用ID的不同集合的数据合并到一个可观察的流中?
我已经阅读并尝试了多个在线示例,每个示例都使用了具有不同嵌套复杂度级别的运算符的不同组合。 https://www.learnrxjs.io/似乎是很好的资源,但它没有提供对我有意义的业务示例。 This question非常相似,也许唯一的不同是使用RxFire进行了一些翻译?还在看着那个。出于比较目的,在SQL中,这是一个SELECT
语句,在引用ID上带有INNER JOIN
。
具体地说,我有一个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 Sessions
的合并集合,其中gameId
实际上被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);
}
我尝试使用pipe
和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?
}
)
}
可能,我只是停留在规范化的思维方式中,因此我愿意就更好的数据管理方式提出建议。我只是不想过多的重复来保持同步。
答案 0 :(得分: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的最新值。如果您有"multiple (..) observables that rely on eachother for some calculation or determination",则可以使用它。
因此,假设您的Game
和GameSession
列表是可观察的,则可以合并每个列表的值。
在switchMap
中,通过遍历GameSessionView
来创建类型为GameSession
的新对象,并使用属性id
,userId
和duration
以及在gameName
的{{1}}的第二个列表中找到Game
的值。请注意,此示例中没有错误处理。
由于gameId
期望您返回另一个Observable,因此合并列表将以switchMap
返回。
最后,您可以of(gameSessionViews)
进行此过程并查看预期的结果。
可以肯定的是,这不是唯一的方法,但我发现它是最简单的方法。