4

目标很简单:使用 、 和 react 本机库连接两个rxjsfirestorerxfire查询rnfirebase

我已经阅读了多个关于加入查询的教程12,但它们都因不同的错误而失败。

//Simple test for collectionData
import { collectionData } from 'rxfire/firestore';

this.myQuery = this.props.docRef.collection(`messages`).where('read', 'array-contains', this.props.me.uid)
collectionData(this.myQuery, 'id').subscribe(docs => console.log(docs))
//Fails with error: this._next is not a function.

或者,

this.publicQuery = this.props.docRef.collection('messages').where('public', '==', true) 
this.myQuery = this.props.docRef.collection(`messages`).where('read', 'array-contains', this.props.me.uid)
const myQuery$ = new Rx.Subject();
const publicQuery$ = new Rx.Subject();
this.myQuery.onSnapshot((querySnapshot) => {
    myQuery$.next(querySnapshot.docs.map(d => d.data()  ));
});
this.publicQuery.onSnapshot((querySnapshot) => {
    publicQuery$.next(querySnapshot.docs.map(d => d.data()  ));
});
const orQuery$ = combineLatest(this.myQuery, this.publicQuery).switchMap((docs) => {
    var [one, two] = docs;
    var combined = one.concat(two);
    return Rx.Observable.of(combined);
})
orQuery$.subscribe((result) => {
    console.log('>>>> ', result)
})
//TypeError: undefined is not a function (near ...switchMap)

如何成功加入两个 Firestore 查询 (OR)?

4

1 回答 1

12

您已经非常接近解决方案了。让我们逐步解决这些问题。

首先,没有必要创建一个Subjectjust 来将您的结果从onSnapshot. 而不是这个:

this.myQuery.onSnapshot((querySnapshot) => {
    myQuery$.next(querySnapshot.docs.map(d => d.data()))
});

我们可以使用“管道转换运算符”来实现相同的目的:

const myQuery$ = this.myQuery.onSnapshot.pipe(
    map(querySnapshot => querySnapshot.docs.map(d => d.data()))
);

另一个查询也是如此:

const publicQuery$ = this.publicQuery.onSnapshot.pipe(
    map(querySnapshot => querySnapshot.docs.map(d => d.data())
);

其次,加入这两个查询,combineLatest确实是正确的创建函数。

但是,您的错误可能是由于您使用了较新的 RxJS 版本,它不再支持“流利”运算符(正式称为“补丁运算符”)。从 RxJS 6 开始,它们已被“管道操作符”取代。例如,myObs$.map(...)已成为myObs$.pipe(map(...)). 这些教程可能使用了旧版本的 RxJS,但仍然可以使用第一个版本。

switchMap此外,如果内部 Observable 只是一个运算符,则不需要使用of。在这种情况下,使用map表现相同的运算符就足够了。

将新的 RxJS 6+ 语法与 结合使用map,组合将如下所示:

const orQuery$ = combineLatest(myQuery$, publicQuery$).pipe(
    map(([one, two]) => one.concat(two))
)

您的其余代码应该是正确的。

旁注:请记住,SQL 中的代码等价于UNION(not JOIN)。为了以JOIN编程方式,您需要将结果集 A 的每个对象与结果集 B 的每个对象组合起来,并为每对创建一个连接对象。这样的无钥匙功能OUTER JOIN看起来像这样(放置在您的map管道中):

one.map(a => 
   two.map(b => Object.assign({}, a, b)))
.reduce((p, c) => p.concat(c), [])

如果您想要一个UNION没有重复对象的对象,请仅连接那些two在 list 中没有匹配主键的项目one。这将是您的映射功能:

one.concat(two.filter(twoItem => !one.some(oneItem => oneItem.id == twoItem.id)))

演示:可以在此处找到使用上述代码和模拟 FireStore 的完整的工作演示:

https://stackblitz.com/edit/rxjs-mefynu?devtoolsheight=60

于 2018-11-27T09:59:11.730 回答