Angular Firestore在两个字段上的多个查询具有可观察性

Angular Firestore在两个字段上的多个查询具有可观察性,angular,google-cloud-firestore,Angular,Google Cloud Firestore,我正在使用Angular和Firestore 我想在两个字段上执行对Firestore数据库的多重查询。现在可以使用WHERE语句进行组合。 我的想法是组合这些值,然后向数据库发送请求。例如,我想回到所有的职位,城市是洛杉矶,旧金山,纽约和星级是5, 4。p> 因此,我必须对6种可能的组合进行查询: Where city = Los Angeles Where Stars = 5 …然后是下一个查询 Where city = Los Angeles Where stars = 4 Where

我正在使用Angular和Firestore

我想在两个字段上执行对Firestore数据库的多重查询。现在可以使用
WHERE
语句进行组合。 我的想法是组合这些值,然后向数据库发送请求。例如,我想回到所有的职位,城市是洛杉矶,旧金山,纽约和星级是5, 4。p> 因此,我必须对6种可能的组合进行查询:

Where city = Los Angeles
Where Stars = 5
…然后是下一个查询

Where city = Los Angeles
Where stars = 4
Where city = San Francisco
Where Stars = 5
Where city = San Francisco
Where Stars = 4
…然后是下一个查询

Where city = Los Angeles
Where stars = 4
Where city = San Francisco
Where Stars = 5
Where city = San Francisco
Where Stars = 4
…然后是下一个查询

Where city = Los Angeles
Where stars = 4
Where city = San Francisco
Where Stars = 5
Where city = San Francisco
Where Stars = 4
等等

我知道如何对一个字段和一个值使用
For
语句,就像您在下面的代码中看到的那样,但我不知道如何组合它们(在多个查询中对组合进行分组),然后等待所有执行(使用可观察项或主题)将它们分组到结果数组中。我在堆栈上找到了两个答案,但没有人真正帮助我做出正确的决定

这一个,但它只在一个领域,而不是观察

另一个 他们提出了“对查询中的一个字段执行过滤,对客户端代码中的另一个字段执行过滤”的好主意 如果结果很少,这个解决方案很好,但是如果结果很多,它会减慢过程,收回我们不需要的数据

export class AnnoncesListComponent implements OnInit {

  queryParams: { departement:string, secteurAct:string };
  subscriptionChange:Subscription;
  annoncesSubscription:Subscription;
  departementGet: any;
  secteurActGet: any;
  annonceQuery: Annonce[];
  isFetchingData:boolean = false;

  constructor( 
    private activeRoute : ActivatedRoute,
    private annnonceService: AnnoncesService 
    ) { }

  ngOnInit() {
//Get QUERYPARAMS FROM THE URL
   this.departementGet = decodeURIComponent(this.activeRoute.snapshot.queryParams['departement']);
   this.secteurActGet =  decodeURIComponent(this.activeRoute.snapshot.queryParams['secteurActivite']);
   this.departementGet = this.departementGet.split('_B2-');
   this.secteurActGet = this.secteurActGet.split('_B2-');

//FOR - TO QUERIES ALL THE DATA NEEDED - FIRST QUERY
   for (var i = 0; i < this.secteurActGet.length; i++) {
    this.annoncesSubscription = this.annnonceService.getAnnonces('secteurActivite', this.secteurActGet[i])
    .subscribe( responseData => {
      this.isFetchingData = false
        this.annonceQuery = responseData.map(item => {
          return {
            id : item.payload.doc.id,
            secteurAct : item.payload.doc.get('secteurActivite'),
            departement : item.payload.doc.get('departement'),
            region : item.payload.doc.get('region'),
            description : item.payload.doc.get('description'),
            infosClefs : item.payload.doc.get('name'),
          } as Annonce;
        })
        console.log(this.annonceQuery);
    });

//FOR - TO QUERIES ALL THE DATA NEEDED - SECOND QUERY
   for (var i = 0; i < this.departementGet.length; i++) {
    this.annoncesSubscription = this.annnonceService.getAnnonces('secteurActivite', this.departementGet[i])
    .subscribe( responseData => {
      this.isFetchingData = false
        this.annonceQuery = responseData.map(item => {
          return {
            id : item.payload.doc.id,
            secteurAct : item.payload.doc.get('secteurActivite'),
            departement : item.payload.doc.get('departement'),
            region : item.payload.doc.get('region'),
            description : item.payload.doc.get('description'),
            infosClefs : item.payload.doc.get('name'),
          } as Annonce;
        })
        console.log(this.annonceQuery);
    });
};
export类AnnoncesListComponent实现OnInit{
查询参数:{department:string,secteurAct:string};
subscriptionChange:订阅;
annoncesSubscription:订阅;
部门设置:任何;
部门行动:任何;
annonRequesty:Annonce[];
isFetchingData:boolean=false;
建造商(
专用activeRoute:ActivatedRoute,
专用ANNONCEService:ANNONCEService
) { }
恩戈尼尼特(){
//从URL获取查询参数
this.departmentGet=decodeURIComponent(this.activeRoute.snapshot.queryParams['department']);
this.secteuracget=decodeURIComponent(this.activeRoute.snapshot.queryParams['secteuractite']);
this.departmentget=this.departmentget.split(“'u B2-”);
this.secteuracget=this.secteuracget.split(“'u B2-”);
//FOR-TO查询所需的所有数据-第一次查询
for(var i=0;i{
this.isFetchingData=false
this.annonRequesty=responseData.map(项=>{
返回{
id:item.payload.doc.id,
secteurAct:item.payload.doc.get('secteuracite'),
部门:item.payload.doc.get('department'),
区域:item.payload.doc.get('region'),
描述:item.payload.doc.get('description'),
infosClefs:item.payload.doc.get('name'),
}曾经;
})
console.log(this.annonRequesty);
});
//FOR-TO查询所需的所有数据-第二次查询
for(var i=0;i{
this.isFetchingData=false
this.annonRequesty=responseData.map(项=>{
返回{
id:item.payload.doc.id,
secteurAct:item.payload.doc.get('secteuracite'),
部门:item.payload.doc.get('department'),
区域:item.payload.doc.get('region'),
描述:item.payload.doc.get('description'),
infosClefs:item.payload.doc.get('name'),
}曾经;
})
console.log(this.annonRequesty);
});
};

我的结果是两个独立的数据,没有组合,并且在每次迭代中创建一个可观察的数据。

我认为使用rxjs/forkJoin处理多个并行请求是一个很好的方法

接受一个可观察的数组作为它的第一个参数,并返回一个可观察的数组,一旦所有传入的可观察的对象都完成,该数组将发出一个可观察的消息

我已经将您的代码重构为更易于阅读的代码,并利用forkJoin并行处理分支和扇区,然后输出每个结果数据的数组

如果您正在处理的数据量相当大,我甚至建议您考虑将cpu密集型操作拆分为多个线程,并避免阻塞主线程

    // map array of departments into an array of Observables
    const departmentsRequests = this.departementGet.map((departement) => {
        return this.annnonceService.getAnnonces('departement', departement);
    });

    const secteurActiviteRequests = this.secteurActGet.map((secteur) => {
        return this.annnonceService.getAnnonces('secteurActivite', secteur);
    });

    // forkJoin takes all Observables and emits once to its subscription
    this.annoncesSubscription = forkJoin([
        forkJoin(departmentsRequests),
        forkJoin(secteurActiviteRequests),
    ]).subscribe(([departaments, secteurs]) => {
        this.isFetchingData = false;

        // all data has been loaded in parallel from firestore, handle it here
    });


服务中用于获取数据的功能如下:

 getAnnonces(champ, valeur){
        return this.firestore.collection('annonce', ref => ref.where(champ, '==', valeur)).snapshotChanges();
      }
我有you’s代码,但当我尝试输出结果时:

 // forkJoin takes all Observables and emits once to its subscription
      this.annoncesSubscription = forkJoin([
          forkJoin(departmentsRequests),
          forkJoin(secteurActiviteRequests),
      ]).subscribe(([departements, secteurs]) => {
          this.isFetchingData = false;
          // all data has been loaded in parallel from firestore, handle it here
          console.log(departements);
      });

没有结果。我尝试使用.get()而不是.snapshotChanges(),但他给了我一个[QuerySnapshot]

非常感谢你宝贵的帮助。我将这样做以加入观察对象,然后使用两个值的组合(部门和部门)对结果进行排序。我想进行这种排序(组合)在查询中,但此解决方案看起来更简单。我将返回该解决方案并发布它是否工作,以获得我需要的结果。我无法在forkJoin之后获取数据。我尝试添加一个运算符以获取有效负载,但它在forkJoin之后似乎不工作,因为它在其他subscribe上工作,而没有对观察值进行分组.我在RXJS上找到了这门课程:我打算去上,因为在能够正确使用它之前,它真的需要对它的工作方式有一个坚实的了解。我不知道在forkJoin操作符之后如何取回有效负载…这是一门很棒的课程!我已经从Todd的座右铭中学习了所有这些课程,并且得到了充分的推荐ayload(结果数据)应该在传递给subscribe方法的回调中可用正在抛出错误,然后从未调用此回调。为什么?subscribe方法接受3个参数,所有这些参数都是回调:1.成功2.错误3.完成如果其中一个观测失败,它将执行错误回调。