【问题标题】:Firestore multiple queries on two fields with observableFirestore 对两个具有可观察的字段的多个查询
【发布时间】:2019-09-15 16:50:04
【问题描述】:

我正在使用 Angular 和 Firestore。

我想在两个字段上对 Firestore 数据库执行多重查询。现在可以使用可以组合的 WHERE 语句。 我的想法是组合这些值,然后向数据库发送请求。例如,我想取回所有城市为洛杉矶、旧金山、纽约且评级为 5、4 的帖子。

所以我必须查询 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

等等。

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

这个,但它只在一个领域,而不是可观察的 Multiple Firestore queries, single promise / callback

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

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

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

【问题讨论】:

    标签: angular google-cloud-firestore


    【解决方案1】:

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

    ForkJoin 接受一个 observable 数组作为它的第一个参数,并返回一个 observable,它在所有传入的 observable 完成后发出。

    我已将您的代码重构为更易于阅读的内容,并利用 forkJoin 并行处理部门和部门,然后输出每个结果数据的数组。

    如果您正在处理的数据量很大,我什至建议您查看WebWorkers,以便将 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
        });
    
    

    【讨论】:

    • 非常感谢您的宝贵帮助。我将这样做以加入可观察对象,然后使用两个值(部门和部门)的组合对结果进行排序。我想在查询中进行这种排序(组合),但这个解决方案看起来更容易。我会带着解决方案回来并发布它是否有效,以获得我需要的结果。
    • forkJoin 后无法获取数据。我试图添加一个运算符来获取有效负载,但它看起来在 forkJoin 之后它不起作用,当它在其他订阅上工作而不对 observables 进行分组时。我在 RXJS 上找到了这门课程:ultimatecourses.com/learn/rxjs-basics,我将学习它,因为它确实需要对其工作方式有深入的了解,然后才能正确使用它。我不明白如何在 forkJoin 运算符之后取回有效负载...
    • 这是一门很棒的课程!我已经从 Todd Motto 学习了所有这些课程,并且完全被推荐。有效负载(结果数据)应该在传入订阅方法的回调中可用。其中一个可观察对象(请求)可能引发错误,然后永远不会调用此回调。为什么? subscribe 方法接受 3 个参数,它们都是回调: 1. 成功 2. 错误 3. 完成 如果其中一个可观察对象失败,它将执行错误回调。也许这就是您没有收到数据的原因。一如既往地查看控制台是否有错误。
    • 您好,谢谢。是的,我现在正在上他的课程,它很棒。我将完成本课程,然后能够修改代码并为这篇文章提供解决方案。 Observable 一开始就很复杂,如果没有良好的基础,就不可能清楚地理解它们是如何工作的。对于回调,如果我一一接受它们的工作,那么当我在 ForkJoin 中同时使用它们时,结果不会回来。
    【解决方案2】:

    服务中取回数据的函数是这个:

     getAnnonces(champ, valeur){
            return this.firestore.collection('annonce', ref => ref.where(champ, '==', valeur)).snapshotChanges();
          }
    

    我有你的代码,但是当我尝试输出结果时:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 2011-06-17
      • 2011-09-15
      • 1970-01-01
      • 2011-11-10
      • 1970-01-01
      相关资源
      最近更新 更多