如何用AngularFire2在Angular5中读取Firestore指定子集合数据
Angular 5 + AngularFire2 实现Firestore分类展示动物信息
我来帮你搞定这个需求,基于你现有的Firestore数据结构就能实现,下面一步步给你讲清楚实现步骤,还会附上可选的模型优化建议。
1. 先确保AngularFire2配置到位
首先要在AppModule里完成AngularFire和Firestore的初始化,记得把Firebase的配置信息填好:
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AngularFireModule } from 'angularfire2'; import { AngularFirestoreModule } from 'angularfire2/firestore'; import { environment } from '../environments/environment'; import { AppComponent } from './app.component'; import { AnimalListComponent } from './animal-list/animal-list.component'; import { AnimalService } from './animal.service'; @NgModule({ declarations: [ AppComponent, AnimalListComponent ], imports: [ BrowserModule, AngularFireModule.initializeApp(environment.firebase), // 填入你的Firebase配置 AngularFirestoreModule ], providers: [AnimalService], bootstrap: [AppComponent] }) export class AppModule { }
2. 创建数据服务(分离业务逻辑)
建议用服务来处理Firestore的数据查询,这样组件代码会更简洁。注意Angular 5对应RxJS 5.x,操作符的导入方式和新版略有区别:
import { Injectable } from '@angular/core'; import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/switchMap'; import 'rxjs/add/observable/forkJoin'; // 定义接口做类型检查,避免出错 export interface Category { name: string; } export interface Animal { name: string; color: string; } @Injectable() export class AnimalService { private categoriesCollection: AngularFirestoreCollection<Category>; constructor(private afs: AngularFirestore) { this.categoriesCollection = this.afs.collection<Category>('Category'); } // 获取所有分类及其下属动物列表 getCategoriesWithAnimals(): Observable<(Category & { id: string, animals: Animal[] })[]> { return this.categoriesCollection.snapshotChanges() // 先转换分类数据,拿到文档ID和基础信息 .map(categoryActions => { return categoryActions.map(action => { const data = action.payload.doc.data() as Category; const id = action.payload.doc.id; return { id, ...data }; }); }) // 遍历每个分类,获取对应的子集合数据 .switchMap(categories => { const animalObservables = categories.map(category => { return this.afs.collection<Animal>(`Category/${category.id}/animalsubcollection`) .valueChanges() .map(animals => ({ ...category, animals })); }); // 合并所有请求结果,返回带动物列表的分类数组 return Observable.forkJoin(animalObservables); }); } }
3. 组件中调用服务并渲染数据
创建一个专门的组件来展示分类和动物列表:
组件TS文件
import { Component, OnInit } from '@angular/core'; import { AnimalService, Category, Animal } from './animal.service'; @Component({ selector: 'app-animal-list', templateUrl: './animal-list.component.html', styleUrls: ['./animal-list.component.css'] }) export class AnimalListComponent implements OnInit { categories: (Category & { animals: Animal[] })[]; constructor(private animalService: AnimalService) { } ngOnInit() { this.animalService.getCategoriesWithAnimals().subscribe(data => { this.categories = data; }); } }
组件HTML模板
按照你要的格式渲染数据,用*ngFor循环遍历,配合titlecase管道让首字母自动大写:
<div *ngFor="let category of categories"> <h3>{{ category.name | titlecase }}</h3> <ul> <li *ngFor="let animal of category.animals"> {{ animal.name | titlecase }}: {{ animal.color | titlecase }} </li> </ul> </div>
可选:数据模型优化建议
你的现有结构已经能满足需求,但可以做些更符合Firestore惯例的调整:
- 集合名用小写复数:把
Category改成categories,animalsubcollection改成animals,更直观易读。 - 分类文档ID可以直接用分类名(比如
reptiles、mammals)代替自动生成的ID,这样查询单个分类时更方便;如果分类是动态添加的,用自动ID也完全没问题。
优化后的结构示例:
categories: { reptiles: { name : "reptiles" animals: { snake_xyz: { name: "snake", color: "white" } lizard_abc: { name: "lizard", color: "black" } } } mammals: { name : "mammals" animals: { monkey_def: { name: "monkey", color: "brown" } cat_ghi: { name: "cat", color: "white" } } } }
如果用这个优化结构,只需要修改服务里的集合路径,把Category改成categories、animalsubcollection改成animals就可以了。
内容的提问来源于stack exchange,提问作者Joel
相关产品推荐
相关产品推荐

