使用 RxJs 和 AngularFirestore 通过外键获取单个文档

Get a single document by foreign key in using RxJs and AngularFirestore

我编写了一个如下所示的查询:

getPaymentByBookingId(id: string): Observable<Payment> {
    return this.afs.collection<Payment>('payments', ref => ref.where('bookingId', '==', id).limit(1))
        .valueChanges()
        .pipe(
            flatMap(array => from(array)),
            first()
        );
}

其中 Payment 对象具有对 Booking id 的唯一引用。我想查找给定 ID 的付款。

这似乎是纠正此查询的一种相当复杂的方法。

是否有更简单的方法来执行此操作 - 包括这里是否有代码味道使这变得困难?

您可以仅使用 Javascript 原生数组 API .find() 来完成,它会为您节省几行代码:

getPaymentByBookingId(id: string): Observable<Payment> {
    return this.afs.collection<Payment>('payments')
        .valueChanges()
        .pipe(
            map(allPayments=>allPayments.find(payment=>payment.bookingId === id))
        );
}

或者您可以使用 .first() 运算符并提供其首次满足的条件:

getPaymentByBookingId(id: string): Observable<Payment> {
    return this.afs.collection<Payment>('payments')
        .valueChanges()
        .pipe(
            flatMap(array => from(array)),
            first(eachPayment => eachPayment.bookingId === id)
        );
}

请注意,过滤在幕后的工作方式存在根本差异。我个人更喜欢 Javascript 的原生函数,因为我觉得使用 from(array) 转换 observable 只是为了让它一个一个地发出数组序列有点多余。

另请注意,通过执行 ref => ref.where('bookingId', '==', id),您的过滤实际上发生在查询级别(也就是不在客户端)。如果你确信检索到的payments个数不会很大,那么让客户端做过滤就好了;否则最好将处理部分卸载到服务器。

更简单一点的是:

getPaymentByBookingId(id: string): Observable<Payment> {
    return this.afs.collection<Payment>('payments', ref => ref.where('bookingId', '==', id).limit(1))
        .valueChanges()
        .pipe(
            map(array => array[0]),
        );
}

如果未找到付款,这将返回 undefined