如何使用rxfire和rxjs(OR查询)加入两个Firestore查询

TIM*_*MEX 2 rxjs firebase google-cloud-firestore rxfire

我们的目标很简单:将两个公司的FireStore查询利用rxjs,rxfire以及rnfirebase反应机库.

我读过多教程1,2上加入查询,但他们都失败,不同的错误.

//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.
Run Code Online (Sandbox Code Playgroud)

或者,

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)
Run Code Online (Sandbox Code Playgroud)

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

ggr*_*nig 8

你已经非常接近解决方案了.让我们一步一步地解决问题.

首先,没有必要创建一个Subjectjust来转换你的结果onSnapshot.而不是这个:

this.myQuery.onSnapshot((querySnapshot) => {
    myQuery$.next(querySnapshot.docs.map(d => d.data()))
});
Run Code Online (Sandbox Code Playgroud)

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

const myQuery$ = this.myQuery.onSnapshot.pipe(
    map(querySnapshot => querySnapshot.docs.map(d => d.data()))
);
Run Code Online (Sandbox Code Playgroud)

其他查询也是如此:

const publicQuery$ = this.publicQuery.onSnapshot.pipe(
    map(querySnapshot => querySnapshot.docs.map(d => d.data())
);
Run Code Online (Sandbox Code Playgroud)

其次,要加入那两个查询,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))
)
Run Code Online (Sandbox Code Playgroud)

其余代码应该是正确的.

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

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

如果您希望UNION没有重复的对象,请仅连接那些two列表中没有匹配主键的项目one.这将是您的映射功能:

one.concat(two.filter(twoItem => !one.some(oneItem => oneItem.id == twoItem.id)))
Run Code Online (Sandbox Code Playgroud)

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

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