一次查询获取4个文档的最佳方法?

时间:2019-11-27 14:40:58

标签: angular typescript firebase google-cloud-firestore angularfire

我正在使用Firebase和angularfire(最新版本)。我的数据模型是:

main

所以基本上我需要在我的模板中显示所有用户的预订: {{reservations.service.name}} {{reservations.venue.name}}等。“主键”是用户ID。 我创建了助手,以获取单个文档:

VENUES {
   [venue.id] {
      name: string
   }
}

SERVICES {
   [document.id] {
      venueid: string
      name: string
      price: number
   }
}

USERS {
   [user.id] {
      name: string;
      phone: number;
   }
}

RESERVATIONS {
   [document.id] {
      uid: <--- userID from users
      serviceid: <--- id of document from services collection
      name: string;
   }
}

因此当我需要获取一份文档时,它可以正常工作。要使用参考获取所有预订信息,

  doc$(path: string): Observable<any> {
    return this.afs
      .doc(path)
      .snapshotChanges()
      .pipe(
        map(doc => {
          return { id: doc.payload.id, ...doc.payload.data() };
        })
      );
  }

我从带有提供的uid的resevations集合中获取了所有文档。

几天前,我开始使用nosql。我对switchmap,map,combinatelatest()进行了一些研究,但我不知道如何使用它。

我的问题是:如何将所有可观察物合并为一个,以根据用户ID获得所有文档? 我需要从预订集合中获取文档,其中用户ID,用户数据和服务数据(基于Reservations.serviceid == services.document.id)

提前谢谢!

顺便说一句。

我尝试使用:

const $reservations = this.afs.collection('reservations', ref => ref.where('uid', '==', userID)).valueChanges();

但是它只允许我将管道与ref.where结合(我不知道serviceid直到获得预订)

2 个答案:

答案 0 :(得分:1)

您可以为此使用Angularfire leftJoin(afs, joinKey, joinCollection, limit=100)函数。

const reservations$ = this.afs.collection('reservations', ref => ref.where('uid', '==', userID)).valueChanges();
const reservationsServices$ = reservations$.pipe( 
  leftJoin(afs, 'serviceid', 'services') 
)

查看详细说明here

答案 1 :(得分:0)

如果有人在寻找快速解决方案加入查询,我建议使用: https://github.com/AngularFirebase/133-firestore-joins-custom-rx-operators

在我的情况下,我使用leftJoinDocument。这是代码:


  leftJoinDocument(field, collection) {
    return source =>
      defer(() => {
        let collectionData;
        const cache = new Map();

        return source.pipe(
          switchMap(data => {
            cache.clear();

            collectionData = data as any[];

            const reads$ = [];
            let i = 0;
            for (const doc of collectionData) {
              if (!doc[field] || cache.get(doc[field])) {
                continue;
              }

              reads$.push(
                this.afs
                  .collection(collection)
                  .doc(doc[field])
                  .valueChanges()
              );
              cache.set(doc[field], i);
              i++;
            }

            return reads$.length ? combineLatest(reads$) : of([]);
          }),
          map(joins => {
            return collectionData.map((v, i) => {
              const joinIdx = cache.get(v[field]);
              return { ...v, [field]: joins[joinIdx] || null };
            });
          }),
          tap(final =>
            console.log(
              `Queried ${(final as any).length}, Joined ${cache.size} docs`
            )
          )
        );
      });

然后在我的页面模块中

  getClientReservations() {
    this.reservations = this.afs.collection('reservations', ref => ref.where('uid', '==', 'MwdM8bak78eE1omf6u04KtqlE2X2'))
      .valueChanges()
      .pipe(
        this.db.leftJoinDocument('uid', 'users'),
        this.db.leftJoinDocument('serviceid', 'services'),
        this.db.leftJoinDocument('venueid', 'venue')
      );
  }

感谢tobias为我提供提示:)