代码之家  ›  专栏  ›  技术社区  ›  Idris.AH

如何在可观测重复数据中过滤和转换数据

  •  0
  • Idris.AH  · 技术社区  · 6 年前

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

    我有另一个模型,它封装了上面的模型-有一个主题名和一个数组中的事件属性,因为一个主题可以有多个事件:

    import { EventSchema } from './eventSchema.model';
    
    export class SubjectEvents {
        subjectName: string;
        eventData: EventSchema[];
    
        constructor(subjectName: string, eventData: EventSchema[]){
            this.subjectName=subjectName;
            this.eventData=eventData;
        }
    }
    

    我在firebase有一个与这些模型匹配的集合。到目前为止,只有两个文件,一个是数学科目,一个是物理科目,每个科目有两个事件。示例数据为: firebase data

    我有一个服务,它获取数据并转换它。在本例中,我希望获取主题(文档)的每个事件并将其放入一个大数组中。也许我需要合并每个文档的输出。。。不知道怎么做。我能在一定程度上做到这一点-但结果是重复出来的,我不明白为什么。请看下面的最终输出屏幕截图。

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

    Duplicated output

    2 回复  |  直到 6 年前
        1
  •  0
  •   Luillyfe    5 年前

    Live example

    我只是想出了一个更好的方法,我创建了一个名为 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);
    
        2
  •  0
  •   Luillyfe    5 年前

    Live working example

    我希望我能帮忙,这是我的建议:使用 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);