2017-03-09 1 views
0

Je travaille sur une application où un entrepreneur peut dire qu'ils sont «disponibles» sur des jours spécifiques et chaque entrepreneur a un «emplacement». Un employeur peut rechercher la disponibilité en fonction du lieu et de la disponibilité.Combiné et filtre observable pour les clés uniques à QueryFirebase

L'emplacement est basé sur GeoFire. Cela renvoie la clé $ des entrepreneurs disponibles.

qui ressemble à ceci:

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(); 

} 

Ensuite, je peux obtenir le availablity en recherchant le nœud firebase qui ressemble à ceci "/ AvailForContractor/$ {horodatage}/$ uid: true"

Voici comment cela fonctionne et il retourne leur profil:

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(); 
} 

J'ai ces 2 fonctionnant indépendamment les uns des autres. J'ai vraiment besoin de savoir sur toutes les clés $ retournées dans la 2ème fonction, celles qui sont disponibles par emplacement dans la 1ère fonction. J'ai seulement besoin de retourner les profils où ces 2 critères sont remplis.

J'ai été déconner avec CombineLatest, mergeMap, withLatestFrom et Filter mais je n'arrive pas à comprendre comment le faire de la bonne façon.

Ma pensée est qu'une fois que je reçois les clés de la 2ème fonction, combiner avec les touches observables GeoFire et filtre unique, alors faire partie:

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

Ce n'est pas complet, mais une mauvaise tentative. ..

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 donne des coups de touches individuelles comme celle-ci par la voie:

3vAWWHaxHRZ94tc8yY08CH3QNQy3, H74INXgYWIMrUcAtZloFGkwJ6Qd2, etc.

Firebase donnera le coup sur un tableau de clés:

[3vAWWHaxHRZ94tc8yY08CH3QNQy3, H74INXgYWIMrUcAtZloFGkwJ6Qd2, J9DHhg5VQrMpNyAN8ElCWyMWh8i2, fdZYKqqiL0bSVF66zGjBhQVu9Hf1 ] 

Le résultat final serait la combinaison unique de ceux d'une manière RX que j'utiliser pour obtenir les profils.

Quelqu'un peut-il aider? Merci!

Répondre

0

Ceci est ma solution. Je suis sûr qu'il y a une meilleure façon de le faire. MISE À JOUR: Meilleure solution ci-dessous.

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); 

    }); 

} 


} 

Cette solution est beaucoup mieux. Celui ci-dessus était vraiment buggy. Cela avait à voir avec le nettoyage du tableau. À la fin de la journée, je devrais exécuter la recherche 2x pour obtenir les bons résultats. Pas acceptable.

Voici une meilleure approche, c'est plus réactif et il n'a pas les bugs ci-dessus. Je suis sûr qu'il y a une meilleure façon de réfracter cela ou de l'améliorer.

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); 
     }); 

    }); 

}