如何预加载数据以避免在 Angular 中多次读取 firebase

How to pre-load data to avoid multiple firebase reads in Angular

问题:每次用户导航到我的网络应用程序中的特定组件时,它都会从 Firebase Firestore 读取大量数据。这会导致对我的 Firestore 数据库进行数十万次不必要的读取。

问题:我如何预加载或“缓存”Firestore 数据,以便网络应用程序可以使用它不管何时任何用户loads/visits站点?

附加信息:

尝试的解决方案:我考虑过让网络应用程序在初始加载时读取集合,然后在用户加载组件时用该数据填充。这将节省一些读取,因为每次用户单击特定组件时都不会读取集合,但它仍然会导致大量读取,因为每次用户刷新/重新访问该站点时都会读取数据。

目标:总的来说,我正在尝试找到一种解决方案来减少我的 Firestore 数据库上的读取次数。我对可能解决问题的其他解决方案持开放态度,即使我必须重新考虑我的方法或使用不同的资源。

代码:

firebase.service.ts:

export class FirebaseService {
  private peoplePath = '/people';
  constructor(private firestore: AngularFirestore) { }

  getAllPeople(): Observable<Person[]> {
    let colRef: AngularFirestoreCollection<any>;
    colRef = this.firestore.collection(this.peoplePath);
    return colRef.snapshotChanges().pipe(
      map(actions => actions.map(a => {
        const data = a.payload.doc.data() as any;
        const id = a.payload.doc.id;
        return { id, ...data };
      }))
    );
  }

  getPerson(personId: string) {
    let itemDoc: AngularFirestoreDocument<Person>;
    let path = this.peoplePath + "/" + personId;
    itemDoc = this.firestore.doc<Person>(path);
    return itemDoc.valueChanges();
  }

  getTopPeople(amount: number): Person[] {
    let topPeople: Person[] = [];
    this.getAllPeople().subscribe(aPeople => {
      let people = aPeople as Person[];
      people.sort((a,b) => (a.total_addresses < b.total_addresses) ? 1 : -1);
      let count = 0;
      for (let p of people) {
        topPeople.push(p);
        count++;
        if (count == amount) {
          break;
        }
      }
      return topPeople;
    });
    return topPeople;
  }

人-search.component.ts:

export class PersonSearchComponent implements OnInit {
  term: string;
  showSearch: boolean = false;
  numOfPeople: number = 20;
  numOfPeopleDisplay: number = 20;
  constructor(private fbService: FirebaseService) { }

  allPeople: Observable<Person[]> = this.fbService.getAllPeople();

  topPeople: Person[] = this.fbService.getTopPeople(20);

  ngOnInit(): void { }

  getPeople() {
    this.topPeople = this.fbService.getTopPeople(this.numOfPeople);
    this.numOfPeopleDisplay = this.numOfPeople;
  }
}

人-search.component.html:

<div>
    <input name="search"  type="text" (focus)="showSearch = true" placeholder="Search for people"  [(ngModel)]="term">
    <div class="personSearchResults" *ngIf="showSearch">
        <table>
            <tbody>
                <tr *ngFor="let person of allPeople | async | personfilter:term">
                    <td><a routerLink="/person-page/{{person.first_name}}_{{person.last_name}}">{{person.first_name}}</a></td>
                    <td><a routerLink="/person-page/{{person.first_name}}_{{person.last_name}}">{{person.last_name}}</a></td>
                </tr>
            </tbody>
        </table>
    </div>
</div>
<div>
    <span>Enter any number: <input type="number" [(ngModel)]="numOfPeople"></span>
    <button (click)="getPeople()">Sort</button>
    <p>Top {{numOfPeopleDisplay}} people by number of addresses:</p>
</div>
<div>
    <table>
        <thead>
            <tr>
                <th>Rank</th>
                <th>Name</th>
                <th>Number of addresses</th>
            </tr>
        </thead>
        <tbody>
            <tr *ngFor="let person of topPeople; let i=index;">
                <td>{{i + 1}}</td>
                <td><a routerLink="/person-page/{{person.first_name}}_{{person.last_name}}">{{person.first_name}} {{person.last_name}}</a></td>
                <td>{{person.total_addresses}}</td>
            </tr>
        </tbody>
    </table>
</div>

如果需要任何其他信息,请告诉我。

您要查找的是 Firestore 的 data bundles, which (according to this page on serving bundled Firestore content from a CDN):

Cloud Firestore bundles allow you to assemble data bundles from common query results on the backend using the Firebase Admin SDK, and serve these pre-computed blobs cached on a CDN. This gives your users a much faster first load experience and reduces your Cloud Firestore query costs.

所以:

  1. 创建一个包含您希望在缓存中的文档的包
  2. 将该包存储在比 Firestore 的 API.
  3. 更便宜的地方
  4. 下载包并将其推送到客户端的本地缓存中。
  5. 然后就用普通的API读取文档,现在都是本地缓存的