Firebase Firestore 数据库在使用 AngularFire 时复制 UI 上的数据

问题描述 投票:0回答:3

我很难确定我的 Angular 13.1 项目中的确切起源问题,该项目使用 @angular/fire 7.4.1 作为数据库。

这个问题似乎适用于我显示来自 Firestore Database 的数据的每个屏幕,通常以列表屏幕的形式。填充列表的数组似乎过度填充了当前存储在我的 Firestore 数据库中的记录的多个实例

下面是团队列表的示例,这是存在问题的屏幕之一。 Lists seem to overpopulate.

但请注意,如果我导航到另一条路线,然后返回到该屏幕,我可以看到显示的正确数量的数据条目。

Expected behaviour DOES exist.

我一直在想,这可能是初始化应用程序或其他问题的问题,但我摸不着头脑。我认为这是一件小事,我希望如此。我之前使用 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 。 User Record in Gif

然后调用团队服务功能:

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() 方法检查订阅中的数组作为防止重复的方法,但无论如何,数组似乎都会填充重复项。

我是否遗漏了这里服务水平的一些重要内容?或者也许我没有正确填充数组。如前所述,这种情况发生在从数据库读取/检索数据的所有屏幕上。

angular typescript firebase duplicates angularfire
3个回答
1
投票

找到了解决我的问题的方法! 主要是和服务有关,把我的订阅变成承诺。 正如 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);
})

0
投票

每次数据库发生更改时,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);
    })
  }
}

0
投票

如果您使用 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
    }
  }
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.