Как я могу объединить два запроса Firestore, используя rxfire и rxjs (запрос OR)
Цель проста: объединить два запроса 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.
С другой стороны,
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)
Как я могу успешно присоединиться к двум запросам пожарного магазина (ИЛИ)?
1 ответ
Вы уже очень близки к решению. Давайте пройдемся по шагам шаг за шагом.
Во-первых, не нужно создавать Subject
просто чтобы превратить ваш результат из 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
если внутренняя наблюдаемая это просто of
оператор. В этом случае достаточно использовать map
оператор, который будет вести себя одинаково.
Использование нового синтаксиса RxJS 6+ вместе с map
, комбинация будет выглядеть так:
const orQuery$ = combineLatest(myQuery$, publicQuery$).pipe(
map(([one, two]) => one.concat(two))
)
Остальная часть вашего кода должна быть правильной.
Примечание: имейте в виду, что эквивалент вашего кода в 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), [])
Если вы хотите иметь UNION
без повторяющихся объектов, конкатенируйте только те элементы из two
которые не имеют соответствующего первичного ключа в списке one
, Это будет ваша функция отображения:
one.concat(two.filter(twoItem => !one.some(oneItem => oneItem.id == twoItem.id)))
ДЕМО: Полная рабочая демонстрация с приведенным выше кодом и смоделированным FireStore может быть найдена здесь: