问题
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