Объединение коллекций Angular Firestore в цепочки

Это трудно объяснить, но я постараюсь. У меня есть настройка структуры базы данных в Firebase следующим образом:

Пользователь (пользователь Firebase)

  • Электронное письмо

Связь

  • Электронное письмо
  • Группа
  • Роль

Детали пользователя

  • Электронное письмо
  • Имя
  • Фамилия
  • Адрес

По сути, я пытаюсь получить текущего пользователя с помощью AngularFireAuth, затем запросить коллекцию сведений о пользователе с помощью user.email, а затем запросить коллекцию Connections с помощью user.email. Наконец, сопоставьте все это с моделью пользователя и сохраните ее в наблюдаемом объекте.

Обновлено:

Я понял, как получить первую коллекцию для наблюдаемого пользователя, но не уверен, куда идти дальше.

    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 };
        })
    ) 
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
0
740
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

мой первоначальный подход к этому состоял бы в том, чтобы создать 2 отдельных наблюдаемых для сведений о пользователе и соединении, а затем использовать combLatest, чтобы получить полный профиль пользователя:

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
    }
)

Еще примеры использования combLatest:

Изучите Rxjs

Я пробовал это именно так, как вы предложили, но мне не удалось заставить это успешно работать. Наблюдаемые объекты connectionCollection$ и userDetailsCollection$ остаются неопределенными, что действительно странно.

Shawn 03.02.2019 18:15

Хм, я бы проверил, исходит ли канал authState сначала, выполнив выход пользователя из системы. Затем проверьте в базе данных, есть ли какой-либо действительный адрес электронной почты, связанный с этим пользователем.

Linh 04.02.2019 17:09

вы также можете использовать для этого forkJoin. forkJoin будет выдавать значения только тогда, когда все наблюдаемые генерируют хотя бы одно значение

O-9 31.07.2020 10:44
Ответ принят как подходящий

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

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 };
    })
) 

Другие вопросы по теме