组合和过滤 Observable 以获取 QueryFirebase 的唯一键
Combined and Filter Observable for Unique Keys to QueryFirebase
我正在开发一个应用程序,承包商可以在特定日期说他们 "available",并且每个承包商都有一个 "location"。雇主可以根据位置和可用性搜索可用性。
该位置基于 GeoFire。这 return 是可用承包商的 $key。
看起来像这样:
geoQueryContractor(radius, lat, lng) {
const subject = new Subject();
this.fbGeoRef = firebase.database().ref('geofire')
this.geoFire = new GeoFire(this.fbGeoRef);
this.geoFire.ref();
this.geoQuery = this.geoFire.query({
center: [lat, lng],
radius: radius
});
this.geoQuery.on("key_entered", function(key, location, distance) {
subject.next(key);
});
return subject.asObservable();
}
接下来,我可以通过搜索如下所示的 firebase 节点来获取可用性“/AvailForContractor/${timestamp}/$uid:true”
这就是它的工作原理,return他们的个人资料:
getAvailablitybyContractor(timestamp) {
const availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
const AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor
//once we have each key, we can map it and create an fb object observable
.map(keyPerContractor => this.db.object(`/users/${keyPerContractor.$key}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
AvailContractors$.subscribe();
}
我让这两个彼此独立工作。我真的需要知道在第二个函数中的所有 $key 的 returned 中,哪些可以在第一个函数中按位置使用。我只需要 return 满足这两个条件的配置文件。
我一直在摆弄 CombineLatest、mergeMap、withLatestFrom 和 Filter,但我不知道如何以正确的方式做到这一点。
我的想法是,一旦我从第二个函数中获得键,将它与 GeoFire observable 结合并过滤唯一键,然后执行此部分:
//once we have each key, we can map it and create an fb object observable
.map(keyPerContractor => this.db.object(`/users/${keyPerContractor.$key}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
这还不完整,但是一次糟糕的尝试...
getAvailablitybyContractor(timestamp, radius, lat, lng) {
const availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
//when we get back the keys, we are going to switch to another obeservables
const AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor
.map(keyPerContractor => keyPerContractor.$key))
.combineLatest(this.geoQueryContractor(radius, lat, lng))
// .withLatestFrom(this.geoQueryContractor(radius, lat, lng), (keysPerContractor, geo) => ( [keysPerContractor, geo] ))
//once we have each key, we can map it and create an fb object observable
// .map(keyPerContractor => this.db.object(`/users/${keyPerContractor.$key}`)))
// //now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
// .mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
AvailContractors$.subscribe();
}
GeoFire 顺便踢出这样的个别按键:
3vAWWHaxHRZ94tc8yY08CH3QNQy3
、H74INXgYWIMrUcAtZloFGkwJ6Qd2
等
Firebase 将踢出一组键:
[3vAWWHaxHRZ94tc8yY08CH3QNQy3, H74INXgYWIMrUcAtZloFGkwJ6Qd2, J9DHhg5VQrMpNyAN8ElCWyMWh8i2, fdZYKqqiL0bSVF66zGjBhQVu9Hf1 ]
最终结果将是那些以我用来获取配置文件的 RX 方式的唯一组合。
有人可以帮忙吗?谢谢!
这是我的解决方案。我相信有更好的方法可以做到这一点。更新:下面更好的解决方案。
static geoArray: Array<string> = [];
constructor(private af: AngularFire, private db: AngularFireDatabase) {
}
getAvailablitybyContractor(timestamp, radius, lat, lng) {
const availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
const AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor.map(keyPerContractor => keyPerContractor.$key)
.filter(key => ContractorService.geoArray.indexOf(key) > -1)
//once we have each key, we can map it and create an fb object observable
.map(keyPerContractor => this.db.object(`/users/${keyPerContractor}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
AvailContractors$.subscribe();
}
geoQueryContractor(radius, lat, lng) {
this.fbGeoRef = firebase.database().ref('geofire')
this.geoFire = new GeoFire(this.fbGeoRef);
this.geoFire.ref();
this.geoQuery = this.geoFire.query({
center: [lat, lng],
radius: radius
});
this.geoQuery.on("key_entered", function(key, location, distance) {
ContractorService.geoArray.push(key);
});
}
}
这个解决方案要好得多。上面那个真的是马车。它与清除阵列有关。在一天结束时,我将不得不执行 2 次搜索才能获得正确的结果。不可接受。
这是一个更好的方法,它更具反应性并且没有上面的错误。我确信有更好的方法来折射或改进它。
getAvailablitybyContractor(timestamp) {
let availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
this.AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor.map(keyPerContractor => keyPerContractor.$key))
//Combine observable from GeoQuery
.combineLatest(this.keys$, (fb, geo) => ([fb, geo]))
// fb, geo are accessible individually
// .filter method creates a new array with all elements that pass the test implemented by the provided function
// key is now iteriable through geo.indexOf
.map(([fb, geo]) => {
return fb.filter(key => geo.indexOf(key) > -1)
})
.map(filteredKeys => filteredKeys.map(keyPerContractor => this.db.object(`/users/${keyPerContractor}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => {
return Observable.combineLatest(fbojs)
})
.do(console.log)
}
getGeoQuery(radius, lat, lng) {
this.geoQuery = this.geoFire.query({
center: [lat, lng],
radius: radius
});
}
geoQueryContractor() {
return this.keys$ = Observable.create(observer => {
var keys = new Array();
this.geoQuery.on("key_entered", (key, location, distance) => {
keys.push(key);
observer.next(keys);
});
});
}
我正在开发一个应用程序,承包商可以在特定日期说他们 "available",并且每个承包商都有一个 "location"。雇主可以根据位置和可用性搜索可用性。
该位置基于 GeoFire。这 return 是可用承包商的 $key。
看起来像这样:
geoQueryContractor(radius, lat, lng) {
const subject = new Subject();
this.fbGeoRef = firebase.database().ref('geofire')
this.geoFire = new GeoFire(this.fbGeoRef);
this.geoFire.ref();
this.geoQuery = this.geoFire.query({
center: [lat, lng],
radius: radius
});
this.geoQuery.on("key_entered", function(key, location, distance) {
subject.next(key);
});
return subject.asObservable();
}
接下来,我可以通过搜索如下所示的 firebase 节点来获取可用性“/AvailForContractor/${timestamp}/$uid:true”
这就是它的工作原理,return他们的个人资料:
getAvailablitybyContractor(timestamp) {
const availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
const AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor
//once we have each key, we can map it and create an fb object observable
.map(keyPerContractor => this.db.object(`/users/${keyPerContractor.$key}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
AvailContractors$.subscribe();
}
我让这两个彼此独立工作。我真的需要知道在第二个函数中的所有 $key 的 returned 中,哪些可以在第一个函数中按位置使用。我只需要 return 满足这两个条件的配置文件。
我一直在摆弄 CombineLatest、mergeMap、withLatestFrom 和 Filter,但我不知道如何以正确的方式做到这一点。
我的想法是,一旦我从第二个函数中获得键,将它与 GeoFire observable 结合并过滤唯一键,然后执行此部分:
//once we have each key, we can map it and create an fb object observable
.map(keyPerContractor => this.db.object(`/users/${keyPerContractor.$key}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
这还不完整,但是一次糟糕的尝试...
getAvailablitybyContractor(timestamp, radius, lat, lng) {
const availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
//when we get back the keys, we are going to switch to another obeservables
const AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor
.map(keyPerContractor => keyPerContractor.$key))
.combineLatest(this.geoQueryContractor(radius, lat, lng))
// .withLatestFrom(this.geoQueryContractor(radius, lat, lng), (keysPerContractor, geo) => ( [keysPerContractor, geo] ))
//once we have each key, we can map it and create an fb object observable
// .map(keyPerContractor => this.db.object(`/users/${keyPerContractor.$key}`)))
// //now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
// .mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
AvailContractors$.subscribe();
}
GeoFire 顺便踢出这样的个别按键:
3vAWWHaxHRZ94tc8yY08CH3QNQy3
、H74INXgYWIMrUcAtZloFGkwJ6Qd2
等
Firebase 将踢出一组键:
[3vAWWHaxHRZ94tc8yY08CH3QNQy3, H74INXgYWIMrUcAtZloFGkwJ6Qd2, J9DHhg5VQrMpNyAN8ElCWyMWh8i2, fdZYKqqiL0bSVF66zGjBhQVu9Hf1 ]
最终结果将是那些以我用来获取配置文件的 RX 方式的唯一组合。
有人可以帮忙吗?谢谢!
这是我的解决方案。我相信有更好的方法可以做到这一点。更新:下面更好的解决方案。
static geoArray: Array<string> = [];
constructor(private af: AngularFire, private db: AngularFireDatabase) {
}
getAvailablitybyContractor(timestamp, radius, lat, lng) {
const availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
const AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor.map(keyPerContractor => keyPerContractor.$key)
.filter(key => ContractorService.geoArray.indexOf(key) > -1)
//once we have each key, we can map it and create an fb object observable
.map(keyPerContractor => this.db.object(`/users/${keyPerContractor}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => Observable.combineLatest(fbojs))
.do(console.log)
AvailContractors$.subscribe();
}
geoQueryContractor(radius, lat, lng) {
this.fbGeoRef = firebase.database().ref('geofire')
this.geoFire = new GeoFire(this.fbGeoRef);
this.geoFire.ref();
this.geoQuery = this.geoFire.query({
center: [lat, lng],
radius: radius
});
this.geoQuery.on("key_entered", function(key, location, distance) {
ContractorService.geoArray.push(key);
});
}
}
这个解决方案要好得多。上面那个真的是马车。它与清除阵列有关。在一天结束时,我将不得不执行 2 次搜索才能获得正确的结果。不可接受。
这是一个更好的方法,它更具反应性并且没有上面的错误。我确信有更好的方法来折射或改进它。
getAvailablitybyContractor(timestamp) {
let availContractorKeys$ = this.db.list(`/AvailForContractor/${timestamp}`);
this.AvailContractors$ = availContractorKeys$
//maping each key
.map(keysPerContractor => keysPerContractor.map(keyPerContractor => keyPerContractor.$key))
//Combine observable from GeoQuery
.combineLatest(this.keys$, (fb, geo) => ([fb, geo]))
// fb, geo are accessible individually
// .filter method creates a new array with all elements that pass the test implemented by the provided function
// key is now iteriable through geo.indexOf
.map(([fb, geo]) => {
return fb.filter(key => geo.indexOf(key) > -1)
})
.map(filteredKeys => filteredKeys.map(keyPerContractor => this.db.object(`/users/${keyPerContractor}`)))
//now we got back an array of firebase object observables (fbojs) and we need to combine them in to one observable
.mergeMap(fbojs => {
return Observable.combineLatest(fbojs)
})
.do(console.log)
}
getGeoQuery(radius, lat, lng) {
this.geoQuery = this.geoFire.query({
center: [lat, lng],
radius: radius
});
}
geoQueryContractor() {
return this.keys$ = Observable.create(observer => {
var keys = new Array();
this.geoQuery.on("key_entered", (key, location, distance) => {
keys.push(key);
observer.next(keys);
});
});
}