如何将两个firebase集合组合成一个新的对象数组

Posted

技术标签:

【中文标题】如何将两个firebase集合组合成一个新的对象数组【英文标题】:How to combine two firebase collections into a new array of objects 【发布时间】:2019-08-27 20:20:37 【问题描述】:

我正在使用 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】:

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

似乎snapshotChanges() 会返回一个 Observable,它不会在发出第一个值时完成。

因此,例如,尝试将forkJoin 替换为zip

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

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

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

【讨论】:

我不得不使用 combineLatest,但这有效。谢谢!

以上是关于如何将两个firebase集合组合成一个新的对象数组的主要内容,如果未能解决你的问题,请参考以下文章

python 两个列表组合成一个新的列表?

如何将来自不同模型的两个查询集组合成一个?

我需要将数组元素中的所有对象组合成一个新的对象数组

对复合集合进行排序

将两个数组 排列组合到一个数组集合 求java 代码

将多个集合组合成一个逻辑集合?