如何将两个Firebase集合合并到一个新的对象数组中

时间:2019-04-05 21:38:16

标签: angular typescript firebase rxjs google-cloud-firestore

我正在使用Angular和Firebase进行一个小项目。日期更改后,我需要获取在该日期或该日期之前创建的“问题”列表,以及当天该问题的单个“答案”。

当前日期是一个BehaviorSubject,因此当它发生更改时,我会使用switchmap获取该日期的问题和答案列表。

但是在使用forkJoin和map将两个数组合并/合并为一个数组之后,似乎没有任何显示。但是,如果我在forkJoin之前简单地返回QuestionsCollection,我会得到问题列表,但这无济于事,因为在那个日期我仍然没有该问题的答案。

因此,在产生forkJoin之前仅返回const q。 如下所示的问题列表(该answer属性是默认值,因为如果数据库中没有我,我会为该用户实例化一个新问题,一旦用户保存得分,便会添加该问题),但使用forkJoin,甚至没有返回[]

[
 {
"id": "e0gdRmeNu2bheekeyT6m",
"uid": "uPhcLZkaRYRXpsSZC0zbRqUOWOq2",
"question": "Combine Q with A",
"goal": 10,
"answer": {
  "id": null,
  "score": null,
  "qid": null,
},
...
]

在firebase中,“答案和问题”是单独的集合,因为用户每天只会收到1个答案,因此当我要求日期问题时,我不想获得所有以前的答案。

主要方法

getQuestions() {
    //Observable<Question[]>
    this.questions = this.dateService.dateStore
        .pipe(
            switchMap(date => {
                const startDate = moment(date).startOf('day').utc().toDate();
                const endDate = moment(date).endOf('day').utc().toDate();

                //Observable<Question[]>
                const q = this.getQuestionsUntilDate(endDate);
                //Observable<Answer[]>
                const a = this.getAnswersForDateRange(startDate, endDate);

                //forkjoin and map results together?
                //doesn't seem to work
                return forkJoin([q, a])
                    .pipe(
                        map(val => {
                            let questions = val[0];
                            let answers = val[1];

                            questions.forEach(question => {
                                //a answer is not guaranteed to exist so only
                                //add it to the question if we found one.
                                const answer = answers.find(answer => answer.qid === question.id);
                                if (answer) {
                                    question.answer = answer;
                                }
                            });

                            return questions;
                        }));
            }))
}

问答集呼叫

    private getQuestionsUntilDate(date: Date) {
    return this.qCollection(ref => ref
        .where('timestamp', '<=', date)
        .where('uid', '==', this.auth.userId)
        .orderBy('timestamp'))
        .snapshotChanges()
        .pipe(
            map(res => {
                return res.map(q => {
                    return new Question({
                        id: q.payload.doc.id,
                        ...q.payload.doc.data()
                    })
                })
            })
        );
}

private getAnswersForDateRange(sDate: Date, eDate: Date) {
    return this.aCollection(ref => ref
        .where('timestamp', '<=', eDate)
        .where('timestamp', '>=', sDate)
        .where('uid', '==', this.auth.userId))
        .snapshotChanges()
        .pipe(
            map(res => {
                return res.map(a => {
                    return new Answer({
                        id: a.payload.doc.id,
                        ...a.payload.doc.data(),
                    })
                })
            })
        );
}

1 个答案:

答案 0 :(得分:1)

forkJoin将在所有这些可观察物完成时发出给定可观察物的最后一个值。

forkJoin marble diagram

似乎snapshotChanges()会返回一个Observable,但不会发出第一个值。

例如,尝试用forkJoin代替zip

zip可让您按照发射顺序组合可观察值:第一个值与第一个值,第二个值与第二个值,等等。

如果您需要对任何流的更新做出反应,请尝试combineLatest

注意 :您需要从zip导入rxjs,而不是rxjs/operators