Angular中Firestore关联数据实现技师评分柱状图显示姓名异常问题
问题分析
你的问题根源在于异步操作的执行顺序不匹配,以及未处理mechanicNames中找不到对应ID的情况:
mechanicQualifications的valueChanges()和mecanicos的get()是两个独立的异步请求,无法保证哪个先完成。如果技师信息请求先返回,此时this.mechanicRatings还未被赋值或仅加载部分数据,会导致chartData生成时name字段为undefined,Highcharts会自动将其转换为0显示。- 若评分记录中的
mechanicId在mecanicos集合中无对应数据,同样会出现name为undefined,最终显示为0。
解决方案
使用RxJS的forkJoin(适用于一次性获取数据)或combineLatest(适用于实时监听评分变化)合并两个异步数据流,确保两者数据都准备好后再生成图表数据,同时添加默认值处理避免显示异常。
修正后的一次性获取数据代码
import { forkJoin } from 'rxjs'; // 定义类型接口 interface MechanicQualification { mechanicId: string; qualification: number; } interface Mechanic { uid: string; name: string; } // 合并两个异步请求,等待两者都完成再处理 forkJoin([ this.firestore.collection<MechanicQualification>('mechanicQualifications').valueChanges(), this.firestore.collection<Mechanic>('mecanicos').get() ]).subscribe(([qualifications, mechanicSnapshot]) => { // 计算每个技师的平均评分 const mechanicRatingsMap: { [mechanicId: string]: number[] } = {}; qualifications.forEach(qualification => { if (!mechanicRatingsMap[qualification.mechanicId]) { mechanicRatingsMap[qualification.mechanicId] = []; } mechanicRatingsMap[qualification.mechanicId].push(qualification.qualification); }); const mechanicRatings = Object.keys(mechanicRatingsMap).map(mechanicId => { const ratings = mechanicRatingsMap[mechanicId]; const average = ratings.reduce((acc, rating) => acc + rating, 0) / ratings.length; return { mechanicId, average }; }); // 构建技师ID到姓名的映射 const mechanicNames: { [mechanicId: string]: string } = {}; mechanicSnapshot.forEach(doc => { const mechanic = doc.data() as Mechanic; mechanicNames[mechanic.uid] = mechanic.name; }); // 生成图表数据,找不到姓名时显示技师ID const chartData = mechanicRatings.map(item => ({ name: mechanicNames[item.mechanicId] || item.mechanicId, y: item.average })); this.createBarChart(chartData); });
关键改进点
- 合并异步数据流:用
forkJoin等待两个请求完成后再处理,避免因顺序问题导致的数据未加载完成。 - 异常值处理:通过
|| item.mechanicId确保找不到对应姓名时,显示技师ID而非0。 - 类型规范:明确定义
Mechanic接口,避免类型断言的模糊性。
实时监听评分变化的优化方案
如果需要实时监听评分更新,可改用combineLatest并将技师信息获取改为valueChanges():
import { combineLatest } from 'rxjs'; combineLatest([ this.firestore.collection<MechanicQualification>('mechanicQualifications').valueChanges(), this.firestore.collection<Mechanic>('mecanicos').valueChanges() ]).subscribe(([qualifications, mechanics]) => { // 计算平均评分逻辑不变 const mechanicRatingsMap: { [mechanicId: string]: number[] } = {}; qualifications.forEach(qualification => { if (!mechanicRatingsMap[qualification.mechanicId]) { mechanicRatingsMap[qualification.mechanicId] = []; } mechanicRatingsMap[qualification.mechanicId].push(qualification.qualification); }); const mechanicRatings = Object.keys(mechanicRatingsMap).map(mechanicId => { const ratings = mechanicRatingsMap[mechanicId]; const average = ratings.reduce((acc, rating) => acc + rating, 0) / ratings.length; return { mechanicId, average }; }); // 从实时数据流中构建姓名映射 const mechanicNames = mechanics.reduce((map, mechanic) => { map[mechanic.uid] = mechanic.name; return map; }, {} as { [mechanicId: string]: string }); const chartData = mechanicRatings.map(item => ({ name: mechanicNames[item.mechanicId] || item.mechanicId, y: item.average })); this.createBarChart(chartData); });
内容的提问来源于stack exchange,提问作者Daniel loaiza
相关产品推荐
相关产品推荐

