我有一个 Firestore 数据库,它的集合排列类似于关系数据库,相关集合存储外键。做出此决定是为了更轻松地与现有 .Net 服务集成,并提供更大的灵活性。
这是数据模型的一部分:
我已将我的状态拆分为功能模块,并具有如下代码:
ngxsOnInit(ctx: StateContext<SchedulesStateModel>) {
ctx.dispatch([
new GetScheduleGroups(),
new GetSchedules()
]);
}
@Selector()
static scheduleGroups(state: SchedulesStateModel): Array<ScheduleGroup> {
return state.scheduleGroups;
}
@Selector()
static scheduleGroupById(state: SchedulesStateModel) {
return (scheduleGroupId: string) => {
return state.scheduleGroups.filter((scheduleGroup: ScheduleGroup) =>
scheduleGroup.id === scheduleGroupId);
};
}
@Action(GetScheduleGroups)
getScheduleGroups({ patchState }: StateContext<SchedulesStateModel>) {
return this.dataService.getDocuments$<ScheduleGroup>('scheduleGroups')
.pipe(tap(scheduleGroups => patchState({ scheduleGroups })));
}
@Action(GetSchedules)
getSchedules({ patchState }: StateContext<SchedulesStateModel>) {
return this.dataService.getDocuments$<Schedule>('schedules')
.pipe(tap(schedules => patchState({ schedules })));
}
在 ScheduleListComponent 中,我有以下代码:
getSchedulesById$(scheduleGroupId: string) {
return this.store.select(SchedulesState.schedulesByGroupId)
.pipe(map(schedulesFilter => schedulesFilter(scheduleGroupId)));
}
我可以将 getSchedulesById$ 的检索逻辑移动到状态类中,但是我目前的代码结构方式是,我需要一种为每个 ScheduleGroup 检索 Schedules 的方法;因为 ScheduleGroup 被迭代并检索每个组的 Schedules 以进行显示。这可以在以下模板片段中看到:
<ngb-tab
*ngFor="let scheduleGroup of (getScheduleGroups$(scheduleGroupCollection.id) | async)"
[title]="scheduleGroup.name">
<ng-template ngbTabContent>
<div class="schedules-container" [ngStyle]="{ height: tabHeight }">
<ibms-schedules-list-item
*ngFor="let schedule of (getSchedules$(scheduleGroup.id) | async)"
[schedule]="schedule">
</ibms-schedules-list-item>
</div>
</ng-template>
</ngb-tab>
这段代码有效,但看起来很冗长。有没有更好的方法来做到这一点?
我遇到的问题之一是,即使是简单的组件最终也会变成容器。以 ScheduleListComponent 为例,它需要显示来自相关表的数据。获取此数据取决于在 *ngFor 迭代期间哪个特定的 Schedule 项处于焦点。
有什么改进的建议吗?我几乎可以肯定有更好的方法,但我不确定它是什么。
另外,这里是数据服务:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { fromPromise } from 'rxjs/internal-compatibility';
import { map } from 'rxjs/operators';
import { AngularFirestore } from 'angularfire2/firestore';
import WhereFilterOp = firebase.firestore.WhereFilterOp;
import { Guid } from 'guid-typescript';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private db: AngularFirestore) {}
getDocuments$<T>(collectionName: string): Observable<T[]> {
return this.db.collection<T>(collectionName).snapshotChanges().pipe(
map(actions => actions.map(action => {
const id = action.payload.doc.id;
const data: T = action.payload.doc.data() as T;
data[ 'id' ] = id;
return <T>data;
}))
);
}
getDocumentsByQuery$<T>(collectionName: string, propertyName: string,
comparisonOperator: WhereFilterOp, targetValue: string | boolean): Observable<T[]> {
return this.db.collection<T>(
collectionName,
ref => ref.where(propertyName, comparisonOperator, targetValue)).snapshotChanges().pipe(
map(actions => actions.map(action => {
const id = action.payload.doc.id;
const data: T = action.payload.doc.data() as T;
data[ 'id' ] = id;
return data;
}))
);
}
addDocument<T>(collectionName: string, document: T) {
const guid: string = Guid.raw();
return fromPromise(this.db.collection<T>(collectionName).doc(guid).set(document))
.pipe(
map(() => {
const returnDocument: T = document;
document[ 'id' ] = guid;
return returnDocument;
})
);
}
addBatch<T>(collectionName: string, documents: Array<T>) {
const batch = this.db.firestore.batch();
const collectionRef = this.db.collection<T>(collectionName);
documents.forEach((document: T) => {
const guid: string = Guid.raw();
const docRef = collectionRef.doc(guid).ref;
batch.set(docRef, document);
});
return fromPromise(batch.commit());
}
updateDocument<T>(collectionName: string, document: T, data: any) {
return this.db.collection<T>(collectionName).doc(document['id']).update(data);
}
deleteDocument<T>(collectionName: string, document: T) {
return this.db.collection<T>(collectionName).doc(document['id']).delete();
}
}
我知道这项服务可以改进,我会开始这样做,但我想我会为了完整起见将它包括在内。
任何改进建议将不胜感激。