How to filter and transform data in Observable - duplicate data
Clash Royale CLAN TAG#URR8PPP
How to filter and transform data in Observable - duplicate data
I have a model of subject events - defines what properties it should have:
export class EventSchema
title: string;
start: string;
end: string;
price: number;
constructor(title: string, start: string, end: string, price: number)
this.title=title;
this.start=start;
this.end=end;
this.price=price;
I have another model that encapsulates the above model - has a subject name and the event properties in an array since there can be multiple events for a single subject:
import EventSchema from './eventSchema.model';
export class SubjectEvents
subjectName: string;
eventData: EventSchema;
constructor(subjectName: string, eventData: EventSchema)
this.subjectName=subjectName;
this.eventData=eventData;
I have a collection in firebase matching these models. So far there are only two documents, one with maths subjects and one with physics subjects, each with 2 events. Example data is:
I have this service which gets the data, and transforms it. In this instance, I want to take each event for a subject (document) and put it into one big array. Maybe I need to merge the output of each document... not sure how. I am able to achieve this somewhat - but the results are coming out duplicated, and I don't understand why. Please see below a screen shot of the final output.
import Injectable from '@angular/core';
import AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument, QuerySnapshot, QueryDocumentSnapshot from 'angularfire2/firestore';
import Observable, of, Subscription from 'rxjs';
import map, filter from 'rxjs/operators';
import 'rxjs/add/operator/mergeMap';
import SubjectEvents from '../_models/subjects/subjectEvents.model';
import EventSchema from '../_models/subjects/eventSchema.model';
@Injectable()
export class SubjectEventsService
subjectEventCollection : AngularFirestoreCollection<SubjectEvents>;
subjectEventDocument : AngularFirestoreDocument<SubjectEvents>;
subjectEvents : Observable<SubjectEvents>;
subjectEvent : Observable<SubjectEvents>;
filteredArr : Observable<any>;
constructor(private afs : AngularFirestore)
//Get user collection on initialise
this.subjectEventCollection = this.afs.collection('subjectEvents');
getSubjectEvents(subjectFilter: string): Observable<SubjectEvents>
this.filteredArr = this.subjectEventCollection.snapshotChanges()
.pipe(map(changes =>
let filteredArr : any = ;
console.log(filteredArr);
return changes
.map(action =>
console.log(action);
const data = action.payload.doc.data() as SubjectEvents;
data.subjectName = action.payload.doc.data().subjectName;
data.eventData = action.payload.doc.data().eventData;
console.log(data);
data.eventData.forEach(result => filteredArr.push(result); console.log(filteredArr));
return filteredArr;
);
));
return this.filteredArr;
.pipe(mergeMap(changes...
return changes.pipe(mergeMap(action...
Observable<SubjectEvents>
Observable<SubjectEvents>
2 Answers
2
Live example
I just came with a better approach, I created a custom operator called hasBeenEmitted
, you just has to provide it the property you want to filter your data.
hasBeenEmitted
const duplicateData = from(data);
const hasBeenEmitted = n => source =>
new Observable(observer =>
const emmited = ;
return source.subscribe(
next(item)
if (emmited.filter(e => e.title !== item.title).length === 0)
emmited.push(item);
observer.next(item);
,
error(err) observer.error(err); ,
complete() observer.complete();
)
);
const source = duplicateData.pipe(
hasBeenEmitted(item => item.title),
map(e => ( value: e.price, start: e.start ))
);
source.subscribe(console.log);
Live working example
I hope I can help, this is my propose: use filter
and map
, but in filter pass through a custom function to achieve your expected results:
filter
map
const duplicateData = from(data);
const emmited = ;
const hasBeenEmitted = (item, emmited) =>
if (emmited.filter(e => e.title !== item.title).length === 0)
emmited.push(item);
return item;
else
return null;
;
const source = duplicateData.pipe(
filter(item => hasBeenEmitted(item, emmited)),
map(e => ( value: e.price, start: e.start ))
);
source.subscribe(console.log);
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I would say you need to
.pipe(mergeMap(changes...
orreturn changes.pipe(mergeMap(action...
because changes is anObservable<SubjectEvents>
and you want to unwind that array toObservable<SubjectEvents>
. It helps with reasoning if you type your parameters. (BTW perhaps bad form to mix pipable operators and non-pipable operators).– Richard Matsen
Aug 11 at 22:05