首页 > 解决方案 > AngularFirestore 动态查询

问题描述

我正在使用 Angular 9.0.4 和 Firestore 数据库,并且我有一些具有不同位置和主题类别的讲师。这个概念是我将选择我的位置和我想要的主题(例如雅典和数学),我会用这些价值观收回教师。我发现 AngularFire 可以做到这一点,但是我需要的一些“combineLatest”运算符已被弃用,尽管我尝试使用最新的 Rxjs 转换文档代码,但我找不到解决方案。下面是我的代码。

home.component.ts

import {Component, OnInit} from '@angular/core';
import {AngularFirestore} from '@angular/fire/firestore';
import 'firebase/firestore';
import {BehaviorSubject, Observable} from 'rxjs';
import {combineLatest, of} from 'rxjs';
import {map} from 'rxjs/operators';


export interface Instructors {
  last_name: string;
  location: string;
  cate: string;
}


@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
  instructors$: Observable<Instructors[]>;
  locationFilter$: BehaviorSubject<string | null>;
  cateFilter$: BehaviorSubject<string | null>;


  constructor(afs: AngularFirestore) {
    this.locationFilter$ = new BehaviorSubject(null);
    this.cateFilter$ = new BehaviorSubject(null);
    this.instructors$ = combineLatest(
      this.locationFilter$,
      this.cateFilter$
    ).map(([location, cate]) =>
      afs.collection<Instructors>('items', ref => {
        let query: firebase.firestore.Query = ref;
        if (location) {
          query = query.where('location', '==', location);
        }
        if (cate) {
          query = query.where('cate', '==', cate);
        }
        return query;
      }).valueChanges()
    );
  }

  ngOnInit() {

  }

  filterByLocation(location: string | null) {
    this.locationFilter$.next(location);
  }

  filterByCate(cate: string | null) {
    this.cateFilter$.next(cate);
  }

}


home.component.html

<div *ngIf="instructors$ | async; let instructors; else loading">
  <ul>
    <li *ngFor="let instructor of instructors">
      {{ instructor.last_name }}
    </li>
  </ul>
  <div *ngIf="instructors.length === 0">No results, try clearing filters</div>
</div>
<ng-template #loading>Loading&hellip;</ng-template>
<div>
  <h4>Filter by</h4>
  <div>
    <h5>Size</h5>
    <button (click)="filterByLocation('Thessaloniki')">Thessaloniki</button>
    <button (click)="filterByLocation('Crete')">Crete</button>
    <button (click)="filterByLocation(null)" *ngIf="this.locationFilter$.getValue()">
      <em>clear filter</em>
    </button>
  </div>
  <div>
    <h5>Color</h5>
    <button (click)="filterByCate('Leadership')">Leadership</button>
    <button (click)="filterByCate('Maths')">Maths</button>
    <button (click)="filterByCate(null)" *ngIf="this.cateFilter$.getValue()">
      <em>clear filter</em>
    </button>
  </div>
</div>

firestore 数据库就像

instructors{

      randomId{

     name: string;
     cate: string;
     location: string;

     }
}

标签: angularfirebasegoogle-cloud-firestorerxjsangularfire

解决方案


您在代码中使用了map运算符,但您需要订阅新的流,在这种情况下,您需要使用switchMap运算符。从 RxJS 6.0 开始(如果我没记错的话)你需要使用 pipeable 操作符。

以下代码应该可以工作:

this.instructors$ = combineLatest([this.locationFilter$, this.cateFilter$]).pipe(
      switchMap(([location, cate]) =>
        afs
          .collection<Instructors>('items', ref => {
            let query: firebase.firestore.Query = ref;
            if (location) {
              query = query.where('location', '==', location);
            }
            if (cate) {
              query = query.where('cate', '==', cate);
            }
            return query;
          })
          .valueChanges()
      )
    );

注意:您也可以使用mergeMapandflatMap代替switchMap. 您可以在此处阅读有关它们的更多信息以及它们之间的区别。


推荐阅读