How to combine two firebase collections into a new array of objects

烈酒焚心 提交于 2019-12-24 05:16:26

问题


I'm working on a small project with Angular and Firebase. When a date is changed I need to get a list of "Questions" that have been created, on or before that date as well as a single "Answer" of that Question for that day.

The current date is a BehaviorSubject so when it changes I use a switchmap to get the list of Questions and Answers for that date.

But it seems after using forkJoin and map to combine/merge the two array's into one nothing is displayed on my page. But if I simply return the QuestionsCollection before I forkJoin, I get the list of questions, but that doesn't help because I still won't have the Answer for that Question on that Date.

So returning only the const q, before the forkJoin will result in. a list of Questions like the below (that answer property is a default because if I don't have one I from the database I instantiate a new one for the user which will be added once they save their score), but using the forkJoin, doesn't even return an []

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

In firebase Answers and Questions are separate collections, because the user will only ever have 1 answer per day I don't want to get all previous answers when I ask for Questions for a Date.

Main Method

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

Question and Answers Collection calls

    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 will emit last values from given observables when all these observables complete.

And it seems like snapshotChanges() returns you an Observable that won't complete with emitting first values.

So try substituting forkJoin with a zip, for example.

zip will let you combine values from the observables in order of emission: 1st value with 1st value, 2nd with 2nd, etc.

If you need to react on updates from any of the streams — try combineLatest.

NOTE: you'll need to import zip from rxjs, not rxjs/operators



来源:https://stackoverflow.com/questions/55543692/how-to-combine-two-firebase-collections-into-a-new-array-of-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!