我正在尝试显示属于用户的所有“练习”。因为“运动”对象可以属于多个用户,所以这是典型的多对多关系。由于文档建议扁平化数据库的结构,因此每个用户都有一个{ $exercise_key: true }
的字典。
经过几个小时的搜索,我终于得到了一些有用的东西,但它很丑陋,看起来非常缓慢而效率低下。我首先从用户那里获得一个可观察的运动键列表,然后对于每个键,我得到一个FirebaseObservableObject,我将其作为'元数据'属性附加。
当我加载页面时,首先我看到一个空子弹列表,然后只有一半的子弹得到他们的文本,然后最后得到其余的。整个过程需要约2秒钟才能显示出来。即使我动态添加新练习而不重新加载页面,也会发生这种“闪烁”。请在https://papa-bear-1f486.firebaseapp.com上自行试用(使用google身份验证)。
我的数据库如下所示:
{
"exercises" : {
"-KeVLI3UbGkRbifLffMa" : {
"createdAt" : 1488748884471,
"name" : "squat1"
},
"-KeVLISTWaXbFxS6yqfv" : {
"createdAt" : 1488748886066,
"name" : "squat2"
},
},
"users" : {
"JtLTkOb8EXTeCeasF6vLpIpoUDB2" : {
"exercises" : {
"-KeVLI3UbGkRbifLffMa" : true,
"-KeVLISTWaXbFxS6yqfv" : true,
}
}
}
}
这是我提出的丑陋代码:
private exercisesKey$: FirebaseListObservable<any[]>;
private exercises$: Observable<any[]>;
constructor(private af: AngularFire, private auth: AuthService) {
const path = '/users/' + auth.id + '/exercises';
this.exercisesKey$ = af.database.list(path);
this.exercises$ = this.exercisesKey$.map((items) => {
items.map(item => {
item.metadata = this.getExercise(item.$key);
return item;
});
return items;
});
getExercise(key: string): FirebaseObjectObservable<IExercise> {
return this.af.database.object('/exercises/' + key);
}
在我看来:
<ul>
<li *ngFor="let exercise of exerciseService.exercises$ | async">
{{ (exercise.metadata | async)?.name }}
</li>
</ul>
所以我想我的问题是:如何获得从密钥列表中创建的可观察对象列表?
的package.json:
"angularfire2": "^2.0.0-beta.5",
"firebase": "^3.5.2",
答案 0 :(得分:1)
除了您想要执行检索每个练习的单个查询之外,您无法做任何事情来避免对每个练习进行查询。但是,您可以稍微简化一下。
您可以使用combineLatest
撰写可观察的练习:
import 'rxjs/add/observable/combineLatest';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/switchMap';
constructor(private af: AngularFire, private auth: AuthService) {
const path = '/users/' + auth.id + '/exercises';
this.exercisesKey$ = af.database.list(path);
this.exercises$ = this.exercisesKey$
.switchMap((items) => items.length === 0 ?
Observable.of([]) :
Observable.combineLatest(...items.map(item => this.getExercise(item.$key)));
);
});
如果运动键列表发生变化或运动本身发生变化,则组合的observable将重新发出练习列表。
如果您只想要练习的快照,并且不希望在练习发生变化时重新发出观察,请使用forkJoin
代替combineLatest
并使用first
完成每项可观察的练习:
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/switchMap';
constructor(private af: AngularFire, private auth: AuthService) {
const path = '/users/' + auth.id + '/exercises';
this.exercisesKey$ = af.database.list(path);
this.exercises$ = this.exercisesKey$
.switchMap((items) => items.length === 0 ?
Observable.of([]) :
Observable.forkJoin(...items.map(item => this.getExercise(item.$key).first()));
);
});
在这两种情况下,您的模板看起来都是这样的:
<ul>
<li *ngFor="let exercise of exerciseService.exercises$ | async">
{{ exercise.name }}
</li>
</ul>