如何使用rxfire和rxjs联接两个Firestore查询(或查询) [英] How can I join two Firestore queries using rxfire and rxjs (OR query)

查看:59
本文介绍了如何使用rxfire和rxjs联接两个Firestore查询(或查询)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标很简单:使用 rxjs rxfire rnfirebase 反应本机库来连接两个Firestore查询.

The goal is simple: to join two firestore queries utilizing rxjs, rxfire, and the rnfirebase react native library.

我已经阅读了多个教程2 关于联接查询,但是它们都失败,并显示不同的错误.

I've read multiple tutorials 1, 2 on joining queries, but they all fail with different errors.

//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)?

How can I successfully join two firestore queries (OR)?

推荐答案

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

You're already very close to the solution. Let's go through the issues step-by-step.

首先,没有必要创建 Subject 只是为了从 onSnapshot 转换结果.代替这个:

First, it's not necessary to create a Subject just to transform your result from onSnapshot. Instead of this:

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

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

We can achieve the same using 'pipeable transformation operators':

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 确实是正确的创建函数.

Second, to join those two queries, combineLatest is indeed the correct creation function.

但是,您的错误可能是由于您使用了较新的RxJS版本而导致的,该版本不支持流利的"运算符().从RxJS 6开始,它们已被管道运算符"所取代.例如, myObs $ .map(...)已成为 myObs $ .pipe(map(...)).这些教程可能会使用旧版本的RxJS,但仍然可以使用第一个版本.

However, your error might result from you using a newer RxJS version, that doesn't support 'fluent' operators (officially called "patch operators") anymore. They have been replaced by 'pipeable operators' from RxJS 6 onwards. As an example, myObs$.map(...) has become myObs$.pipe(map(...)). The tutorials probably use an older version of RxJS where the first is still possible.

此外,如果内部Observable只是 of 运算符,则不必使用 switchMap .在这种情况下,使用 map 运算符就足够了,它的行为将相同.

Also, it shouldn't be necessary to use switchMap if the inner Observable is just an of operator. It is sufficient in this case to use the map operator, which will behave equally.

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

Using the new RxJS 6+ syntax together with map, the combination will look like this:

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

其余代码应该正确.

侧面说明:请记住,SQL中的代码等效于 UNION (不是 JOIN ).为了以编程方式 JOIN ,您需要将结果集A的每个对象与结果集B的每个对象组合在一起,并为每对创建一个连接的对象.这样的无键 OUTER JOIN 函数看起来像这样(放在您的 map 管道中):

Side Note: Keep in mind that the equivalent of your code in SQL is UNION (not JOIN). In order to JOIN programatically, you'd need to combine each object of result set A with each object of result set B and create a joined object for each pair. Such a function for a keyless OUTER JOIN would look like this (placed in your map pipe):

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

如果您要拥有一个没有重复对象的 UNION ,请仅合并 two 中那些在列表 one .这将是您的映射功能:

If you want to have a UNION with no duplicate objects, concat only those items from two that have no matching primary key in list one. This would be your mapping function:

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

演示:可以在此处找到包含以上代码和模拟FireStore的完整且有效的演示:

DEMO: A complete, working demo with the above code and a simulated FireStore can be found here:

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

这篇关于如何使用rxfire和rxjs联接两个Firestore查询(或查询)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆