Angular Firestore问题:如何将表格数据保存至新集合/文档
问题描述
我开发了一款Angular应用,从Firestore的users集合中以clubId作为关联键获取数据,统计每个clubId对应的用户数量,并将俱乐部名称、关联用户数、计算得出的俱乐部应付金额展示在HTML表格中。目前尝试将该表格数据保存至Firestore的revenueReports集合时,仅能保存空数组和时间戳字段,无法正确存储表格数据,求解决方法。
相关代码
club-count-service.ts 数据获取代码
getClubCounts() { return this.firestore.collection<MyData>('users').get().pipe( map(snapshot => { const clubCounts: any = {}; snapshot.docs.forEach(doc => { const clubId = doc.data().clubId; if (clubCounts[clubId]) { this.club = doc.data().club clubCounts[clubId]++; } else { clubCounts[clubId] = 1; } }); const clubData: ClubData[] = []; Object.entries(clubCounts).forEach(([clubId, count]) => { this.firestore.doc(`clubs/${clubId}`).valueChanges().subscribe((club: any) => { clubData.push({ clubId, clubName: club.name, count }); }); }); return clubData; }), takeUntil(this.dataReadySubject) ); }
组件代码
clubCounts$: any; ngOnInit(): void { this.clubCounts$ = this.myDS.getClubCounts(); }
HTML表格代码
<table class="table rounded-3 border-dark table-light table-sm table-striped table-hover table-bordered caption-top animate shadow table-responsive"> <thead class="table-dark"> <tr> <th>Club Name</th> <th>Count</th> <th>Club Yearly</th> </tr> </thead> <tbody> <tr *ngFor="let club of clubCounts$ | async"> <td>{{ club.clubName}}</td> <td>{{ club.count }}</td> <td>{{ club.count * 2 | currency}}</td> </tr> </tbody> </table>
尝试的保存代码
// Function to save the clubCounts data to Firestore saveClubCountsToFirestore(clubCounts: any) { const dateSaved = new Date(); // You can also use serverTimestamp() if needed // Create a document in the 'revenueReports' collection this.afs.collection('revenueReports').add({ dateSaved, clubCounts, // Assuming 'clubCounts' contains your data fetched from 'getClubCounts()' }) .then(() => { console.log('ClubCounts data saved to Firestore.'); }) .catch(error => { console.error('Error saving clubCounts data to Firestore:', error); }); } // Event handler for the button click onButtonClick() { // Access your clubCounts data from the 'clubCounts$' observable this.clubCounts$.subscribe((clubCountsData: ClubData) => { // Save the clubCounts data to Firestore this.saveClubCountsToFirestore(clubCountsData); }); }
解决方案
问题根源
- 异步操作未等待完成:
getClubCounts方法中,遍历clubCounts时调用的valueChanges()是异步操作,但你直接同步返回了clubData数组——此时数组还未被填充数据,所以返回的是空数组。 - 类型标注错误:保存时
clubCountsData标注为ClubData,但实际应为ClubData[]数组(不过这不是核心问题)。
修复步骤
1. 修正getClubCounts方法,等待所有俱乐部数据加载完成
使用forkJoin合并所有俱乐部文档的异步请求,确保所有数据加载完成后再返回:
import { forkJoin } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; getClubCounts() { return this.firestore.collection<MyData>('users').get().pipe( map(snapshot => { const clubCounts: any = {}; snapshot.docs.forEach(doc => { const clubId = doc.data().clubId; // 简化计数逻辑 clubCounts[clubId] = (clubCounts[clubId] || 0) + 1; }); return clubCounts; }), switchMap(clubCounts => { // 生成所有俱乐部文档的请求数组 const clubRequests = Object.entries(clubCounts).map(([clubId, count]) => { // 使用get()而非valueChanges(),只获取一次数据 return this.firestore.doc(`clubs/${clubId}`).get().pipe( map(doc => { const club = doc.data(); // 处理俱乐部不存在的情况 return { clubId, clubName: club?.name || '未知俱乐部', count }; }) ); }); // 等待所有请求完成后返回结果数组 return forkJoin(clubRequests); }), takeUntil(this.dataReadySubject) ); }
2. 修正保存逻辑的类型和订阅
确保订阅时获取到完整数组,类型匹配:
// 组件中的点击事件处理 onButtonClick() { this.clubCounts$.subscribe((clubCountsData: ClubData[]) => { // 先打印确认数据是否正确 console.log('待保存数据:', clubCountsData); this.saveClubCountsToFirestore(clubCountsData); }); } // 保存方法优化类型 saveClubCountsToFirestore(clubCounts: ClubData[]) { const dateSaved = new Date(); this.afs.collection('revenueReports').add({ dateSaved, clubCounts, }) .then(() => console.log('数据保存成功')) .catch(err => console.error('保存失败:', err)); }
额外优化建议
- 使用
get()替代valueChanges():只需要一次性获取俱乐部数据,不需要实时监听变化,避免不必要的订阅占用资源。 - 添加加载状态:在组件中增加
isLoading变量,数据未加载完成时禁用保存按钮,防止用户误操作。 - 错误处理:在
forkJoin中添加错误捕获,避免单个俱乐部请求失败导致整个流程中断。
内容的提问来源于stack exchange,提问作者Michael Cockinos
相关产品推荐
相关产品推荐

