基于 geofireX 位置的内部连接集合
Inner join collections based on locations with geofireX
我想使用 geofirex 根据用户的位置获取并加入多个集合:
这是我根据位置获取用户文档时的代码:
PS(此代码 returns 仅基于位置的用户文档)
getAround() {
const center = geo.point(this.lat, this.lng);
const field = 'location';
this.points = this.radius.pipe(
switchMap(r => {
return this.geo.query(locations).within(center, r, field, { log: true });
})
);
}
我如何使用 Rxjs 内部连接集合:
getAll() {
const allPosts = this.afStore.collection<Service>('services')
.valueChanges()
.pipe(
switchMap(services => {
const res = services.map((service: Service) => {
return this.afStore.doc<UserModel>(`users/${service.userId}`)
.valueChanges()
.pipe(
map(user => Object.assign(service, { user }))
);
});
return combineLatest([...res]); })
)
.pipe(
switchMap(servuser => {
const ress = servuser.map((service: Service) => {
return this.afStore.doc<Category>(`categorys/${service.iconId}`)
.valueChanges()
.pipe(
map(category => Object.assign(service, { category }))
);
});
return combineLatest([... ress]);
})
);
return allPosts;
}
问题是我不能将这些代码混合在一起,所以我可以根据用户的位置加入我的数据,
我明白了error:
(alias) interface Service
import Service
Argument of type '(service: Service) => Observable<Service & { user: UserModel; }>' is not assignable to parameter of type '(value: GeoQueryDocument, index: number, array: GeoQueryOocument[]) => Observable<Service & { user: UserModel; }>'. Types of parameters 'service' and 'value' are incompatible.
Type 'GeoQuerpocument' is missing the following properties from type 'Service': id, cost, dateCreated, discount, and 6 more.
错误表明 services
来自 value-index-array 类型,而您隐含地期望服务数组。
.pipe(
switchMap(services => { // <-- expects a Service array (but appreantly it's not)
const res = services.map((service: Service) => { // <-- because of this
return this.afStore.doc<UserModel>(`users/${service.userId}`)
.valueChanges()
.pipe(
map(user => Object.assign(service, { user }))
);
});
return combineLatest([...res]); })
)
您可能想看看这个 。他们逐步解释了与您类似的情况。
他们还分享了一个 DEMO:一个完整的、有效的演示,包含上述代码和一个模拟的 FireStore。
除此之外,我还发现了有关 Join Collections in Firestore 的内容,您可能会感兴趣。
我建议看一下前面的问题。无论如何,我将在这里添加一些值得注意的事情:
- You can use
pipeable transformation operators
:
const myQuery$ = this.myQuery.onSnapshot.pipe(
map(querySnapshot => querySnapshot.docs.map(d => d.data()))
);
- To join those two queries,
combineLatest
is the correct creation function.
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.
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.
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))
)
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), [])
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)))
添加这个修复了它,现在我的代码可以工作了!
.pipe(
switchMap(services => {
const res = services.map((fromservices) => {
return this.afStore.doc<UserModel>(`users/${fromservices['userId']}`)
.valueChanges()
.pipe(
map(user => Object.assign(fromservices, { user }))
);
});
return combineLatest([...res]); })
)
只是收到这个警告,我想这没问题吧? :
object access via string literals is disallowed (no-string-literal)tslint(1)
我想使用 geofirex 根据用户的位置获取并加入多个集合:
这是我根据位置获取用户文档时的代码: PS(此代码 returns 仅基于位置的用户文档)
getAround() {
const center = geo.point(this.lat, this.lng);
const field = 'location';
this.points = this.radius.pipe(
switchMap(r => {
return this.geo.query(locations).within(center, r, field, { log: true });
})
);
}
我如何使用 Rxjs 内部连接集合:
getAll() {
const allPosts = this.afStore.collection<Service>('services')
.valueChanges()
.pipe(
switchMap(services => {
const res = services.map((service: Service) => {
return this.afStore.doc<UserModel>(`users/${service.userId}`)
.valueChanges()
.pipe(
map(user => Object.assign(service, { user }))
);
});
return combineLatest([...res]); })
)
.pipe(
switchMap(servuser => {
const ress = servuser.map((service: Service) => {
return this.afStore.doc<Category>(`categorys/${service.iconId}`)
.valueChanges()
.pipe(
map(category => Object.assign(service, { category }))
);
});
return combineLatest([... ress]);
})
);
return allPosts;
}
问题是我不能将这些代码混合在一起,所以我可以根据用户的位置加入我的数据,
我明白了error:
(alias) interface Service
import Service
Argument of type '(service: Service) => Observable<Service & { user: UserModel; }>' is not assignable to parameter of type '(value: GeoQueryDocument, index: number, array: GeoQueryOocument[]) => Observable<Service & { user: UserModel; }>'. Types of parameters 'service' and 'value' are incompatible.
Type 'GeoQuerpocument' is missing the following properties from type 'Service': id, cost, dateCreated, discount, and 6 more.
错误表明 services
来自 value-index-array 类型,而您隐含地期望服务数组。
.pipe(
switchMap(services => { // <-- expects a Service array (but appreantly it's not)
const res = services.map((service: Service) => { // <-- because of this
return this.afStore.doc<UserModel>(`users/${service.userId}`)
.valueChanges()
.pipe(
map(user => Object.assign(service, { user }))
);
});
return combineLatest([...res]); })
)
您可能想看看这个
他们还分享了一个 DEMO:一个完整的、有效的演示,包含上述代码和一个模拟的 FireStore。
除此之外,我还发现了有关 Join Collections in Firestore 的内容,您可能会感兴趣。
我建议看一下前面的问题。无论如何,我将在这里添加一些值得注意的事情:
- You can use
pipeable transformation operators
:
const myQuery$ = this.myQuery.onSnapshot.pipe(
map(querySnapshot => querySnapshot.docs.map(d => d.data()))
);
- To join those two queries,
combineLatest
is the correct creation function.
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 bypipeable operators
from RxJS 6 onwards. As an example,myObs$.map(...)
has becomemyObs$.pipe(map(...))
. The tutorials probably use an older version of RxJS where the first is still possible.
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 themap
operator, which will behave equally.
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))
)
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), [])
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)))
添加这个修复了它,现在我的代码可以工作了!
.pipe(
switchMap(services => {
const res = services.map((fromservices) => {
return this.afStore.doc<UserModel>(`users/${fromservices['userId']}`)
.valueChanges()
.pipe(
map(user => Object.assign(fromservices, { user }))
);
});
return combineLatest([...res]); })
)
只是收到这个警告,我想这没问题吧? :
object access via string literals is disallowed (no-string-literal)tslint(1)