我很难确定我的 Angular 13.1 项目中的确切起源问题,该项目使用 @angular/fire 7.4.1 作为数据库。
这个问题似乎适用于我显示来自 Firestore Database 的数据的每个屏幕,通常以列表屏幕的形式。填充列表的数组似乎过度填充了当前存储在我的 Firestore 数据库中的记录的多个实例
但请注意,如果我导航到另一条路线,然后返回到该屏幕,我可以看到显示的正确数量的数据条目。
我一直在想,这可能是初始化应用程序或其他问题的问题,但我摸不着头脑。我认为这是一件小事,我希望如此。我之前使用 AngularFire 在 Firestore 数据库上完成了项目。
上面的列表是通过 ngOnInit() 调用填充的 :
private loadTeamsList(){
if(!this.currentUser.teams) return;
for(var i = 0;i < this.currentUser.teams.length; i++){
/*
Where this.currentUser.teams[i] is the Firebastore document id of the team
*/
this.teamsService.getTeam(this.currentUser.teams[i]).subscribe( team => {
this.teamsList.push(team);
})
}
}
当前读取的记录是 this ,该记录只包含一个 teamId 。
然后调用团队服务功能:
export class TeamService {
private endpointPrefix = '/teams'
constructor(private firebaseService: FirebaseService) { }
getTeam(teamId: string): Observable<Team>{
return this.firebaseService.getById(teamId,this.endpointPrefix);
}
...
这会导致主要的“父”服务 FirebaseService,我通常尝试在其中进行大部分服务调用。
@Injectable({
providedIn: 'root'
})
export class FirebaseService{
constructor(private firestore: Firestore){ }
...
getById(id: string | null,endpointPrefix: string): Observable<any>{
const ref = doc(this.firestore,endpointPrefix + `/${id}`);
return docData(ref, { idField: 'id' }) as Observable<any>;
}
getAll(endpointPrefix: string): Observable<any[]> {
const ref = collection(this.firestore, endpointPrefix);
return collectionData(ref, { idField: 'id' }) as Observable<any[]>;
}
get firestoreRef(){
return this.firestore;
}
我已经尝试使用 includes() 方法检查订阅中的数组作为防止重复的方法,但无论如何,数组似乎都会填充重复项。
我是否遗漏了这里服务水平的一些重要内容?或者也许我没有正确填充数组。如前所述,这种情况发生在从数据库读取/检索数据的所有屏幕上。
找到了解决我的问题的方法! 主要是和服务有关,把我的订阅变成承诺。 正如 Frank 上面所描述的,看起来订阅正在保留该数据(这已经被理解为缓存),然后订阅被触发,使得该数据在 UI 上“重复”
//Service Call for getting list data (getAll)
async getAllAsync(endpointPrefix: string){
let response : any[] = [];
const ref = collection(this.firestore, endpointPrefix);
const q = query(ref);
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
let resDocument = {
id : doc.id,
...doc.data()
}
response.push(resDocument);
});
if(response){
return response;
} else {
console.log("No response")
return null;
}
}
//Service Call for getting specific document data (getById)
async getByIdPromise(id: string | null,endpointPrefix: string): Promise<any>{
let response : any;
const ref = doc(this.firestore,endpointPrefix + `/${id}`);
const docSnap = await getDoc(ref);
if(docSnap.data()){
response = docSnap.data();
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
//return docData(ref, { idField: 'id' }) as Observable<any>;
if(response){
//console.log(response)
return response;
} else {
console.log("No records with ladder Id found")
return null
}
}
然后我更新了我的 TeamService 呼叫:
getTeam(teamId: string): Promise<any>{
return this.firebaseService.getByIdPromise(teamId,this.endpointPrefix);
}
最后在我的组件中将我的 .subscribe 更改为 .then。
this.teamsService.getTeam(this.currentUser.teams[i]).then( team => {
this.teamsList.push(team);
})
每次数据库发生更改时,Firestore SDK 都会调用您的代码,并提供您订阅的数据的完整列表。因此,在从数据库添加项目之前,您通常需要清除 UI 中的任何现有项目。
我不确定,但这可能意味着在您的
loadTeamsList
中,您必须先清除 this.teamsList
,然后才能将 getTeam
中的项目添加到其中:
private loadTeamsList(){
if(!this.currentUser.teams) return;
this.teamsList = []; // 👈 Start with an empty list again, before adding the ones from the database
for(var i = 0;i < this.currentUser.teams.length; i++){
this.teamsService.getTeam(this.currentUser.teams[i]).subscribe( team => {
this.teamsList.push(team);
})
}
}
如果您使用 AngularFireStore,可以通过以下实现实现相同的结果:
async getAllAsync(endpointPrefix: string): Promise<any[]> {
let response: any[] = [];
try {
const collectionRef = this.firestore.collection(endpointPrefix);
const querySnapshot = await collectionRef.get().toPromise();
querySnapshot!.forEach((doc) => {
let resDocument: YourDataType = <YourDataType ><unknown>doc.data();
resDocument.id = doc.id;
response.push(resDocument);
});
return response; // Return the response array
} catch (error) {
console.error("Error fetching documents:", error);
return []; // Return null in case of an error
}
}