Как объединить и наблюдать две коллекции в Firestore на основе ссылочного идентификатора в документах? - PullRequest
1 голос
/ 07 мая 2019

Я создаю приложение StencilJS (без фреймворка) с бэкэндом Google Firestore и хочу максимально использовать библиотеки RxFire и RxJS для упрощения кода доступа к данным. Как я могу объединить в один наблюдаемый поток данных, поступающих из двух разных коллекций, которые используют ссылочный идентификатор?

В Интернете есть несколько примеров, которые я прочитал и попробовал, каждый из которых использует различную комбинацию операторов с разным уровнем вложенности. https://www.learnrxjs.io/ кажется хорошим ресурсом, но он не дает примеров для бизнеса, которые имеют смысл для меня. Этот вопрос очень похож, и, возможно, единственное отличие - это какой-то перевод в использование RxFire? Все еще смотрю на это. Просто для сравнения, в SQL это будет оператор SELECT с 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?
        }
    )
}

Возможно, я просто застрял в нормальном мышлении, поэтому я открыт для предложений о лучших способах управления данными. Я просто не хочу слишком много дублирования для синхронизации.

1 Ответ

0 голосов
/ 19 мая 2019

Вы можете использовать следующий код (также доступен как 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 вы можете комбинировать последние значения из множества Обервабли. Его можно использовать, если у вас есть "несколько (..) наблюдаемых, которые полагаются друг на друга для какого-либо вычисления или определения" .
Таким образом, предполагая, что списки Game s и GameSession s являются наблюдаемыми, вы можете комбинировать значения каждого списка.
В switchMap вы создаете новые объекты типа GameSessionView, перебирая свои GameSession s, используя атрибуты id, userId и duration и находя значение для gameName во втором списке Game с gameId. Имейте в виду, что в этом примере нет обработки ошибок.
Поскольку switchMap ожидает, что вы вернете другую Наблюдаемую, объединенный список будет возвращен с of(gameSessionViews).
Наконец, вы можете subscribe к этому процессу и увидеть ожидаемый результат.

Конечно, это не единственный способ сделать это, но я считаю это самым простым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...