How to perform operations on 2 separate data collections in 1 function in RxJS so that it returns observable -> as for now it returns Void ? This function is running inside Service of course, and finally I want to subscribe to it in my component.
I assume it requires refactoring, I'm still learning RxJS :)
My attempt (it does not work): https://pastecode.io/s/m1g7a861
// use interface instead class for TS
export interface Task {
goal_id: string;
name: string;
description: string;
priority: string;
taskDate: string;
id: string; // key collection
}
// Base Goal Model
export interface Goal {
name: string;
isMainGoal: boolean;
details: string;
category: string;
lifeArea: string;
creationDate: string;
priority: string;
endDate: Date;
id: string;
}
class MyService {
getTasksByCategory(category:string):Observable<any> {
const daysFromThisWeek = this.getDaysFromThisWeek();
return forkJoin({
tasks: this.tasksS.tasksCollection(),
goals: this.goalsS.goalsCollection(),
})
// !!! OPERATIONS ON GOALS !!!
.pipe(
// filter goals with category from parameter
map(({ tasks, goals }) => {
return goals.filter((item:any) => item.category === category);
}),
// get ID's of found goals in the previous step
map((goals:any) => {
const goalsIDs = goals.map((item:any) => item.id);
return goalsIDs;
})
)
// !!! OPERATIONS ON TASKS !!!
.pipe(
// get IDs-matching-tasks
map(({ tasks, goalsIDs }) => {
let modArr = [] as any;
goalsIDs.forEach((goalId:any) => {
const forModArr = tasks.filter((task:any) => task.goal_id === goalId);
modArr = modArr.concat(forModArr);
})
return modArr;
}),
map(tasksArr => {
// get number of IDs-matching-tasks on each week day
let finalTasks = [] as any;
daysFromThisWeek.forEach((day:any) => {
const forFinalTasks = tasksArr.filter((task:any) => task.taskDate === day);
finalTasks = finalTasks.concat(forFinalTasks.length);
})
return finalTasks;
})
)
}
getDaysFromThisWeek() {
let daysArr = [];
for(let i=1; i<=7; i++) {
daysArr.push(dayjs().startOf('week').add(i, "day").format('YYYY-MM-DD'));
}
return daysArr;
}
}
You're almost there. You are only returning the goalsIDs
from the first pipe
, so the input for the second pipe
do not get the tasks
emissions. Also as mentioned in the comments, having multiple pipe
s to the same input observable isn't different from having a single pipe
containing all operators.
Instead of performing the map
opearations of this.goalsS
observable after the forkJoin
, perform it before. Then you could use the goalIds
to filter the emission of tasksS
observable.
Also I'm certain the filtering operations on tasks emissions could be done better, but I'll leave that to you.
Try the following
getTasksByCategory(category: string): Observable<any> {
const goalIds$ = this.goalsS.tasksCollection().pipe(
map((goals) =>
goals
// filter goals with category from parameter
.filter((goal: any) => goal.category === category)
// get ID's of found goals in the previous step
.map((goal: any) => goal.id)
)
);
const tasks$ = this.tasksS.goalsCollection();
const daysFromThisWeek = this.getDaysFromThisWeek();
return forkJoin({
goalIds: goalIds$,
tasks: tasks$,
}).pipe(
// get IDs-matching-tasks
map(({ tasks, goalIds }) => {
let modArr = [] as any;
goalsIDs.forEach((goalId:any) => {
const forModArr = tasks.filter((task:any) => task.goal_id === goalId);
modArr = modArr.concat(forModArr);
})
return modArr;
}),
map(tasksArr => {
// get number of IDs-matching-tasks on each week day
let finalTasks = [] as any;
daysFromThisWeek.forEach((day:any) => {
const forFinalTasks = tasksArr.filter((task:any) => task.taskDate === day);
finalTasks = finalTasks.concat(forFinalTasks.length);
});
return finalTasks;
})
)
}
Edit: Added brief info about error in OP's code