【问题标题】:Referencing a field on document in Angular Firestore在 Angular Firestore 中引用文档上的字段
【发布时间】:2019-12-10 18:28:46
【问题描述】:

我正在尝试引用 component.ts 文件中文档的其中一个字段。 只要我明确声明let day = "Sunday",下面的代码就可以工作。

由于 this.meter 中有一个字段“day”,我希望能够改为声明 let day = this.meter.day。我知道我必须以某种方式订阅this.meter,但我不知道如何订阅。

我浏览了所有文档,完全不知所措,非常困惑,因为这应该是一个相对简单的操作。

谢谢。

import { Component, OnInit, ViewChild, ElementRef, HostListener, AfterViewInit } from '@angular/core';
import { AngularFirestore, AngularFirestoreDocument, AngularFirestoreCollection, AngularFirestoreCollectionGroup } from '@angular/fire/firestore';
import { Observable, Subscriber } from 'rxjs';
import { ActivatedRoute } from '@angular/router';

export interface Meter { meter: string; units: number; lastupdated: string; year: string; month: string; day: string; monthday: string}

@Component({
  selector: 'app-meter',
  templateUrl: './meter.component.html',
  styleUrls: ['./meter.component.scss']
})

export class MeterComponent implements OnInit {
  meterId: string;
  private meterDoc: AngularFirestoreDocument<Meter>;
  meter: Observable<Meter>;
  dailydata: Observable<any>;
  todayinweek: Observable<any>;
  pastweek: Observable<any>;
  day: string;

  constructor(
    private route: ActivatedRoute, private db: AngularFirestore, private afs:AngularFirestore) {
    this.meterId = this.route.snapshot.paramMap.get('id');
    this.meter = this.afs.doc<Meter>(`meters/${this.meterId}`).valueChanges();
    }

ngOnInit() {


**//let day = this.meter.day;**
let day = "Sunday";


 this.dailydata = this.db.collection('meters').doc<any>(this.meterId).collection('dailydata').doc(day).valueChanges();
 this.todayinweek = this.db.collection('meters').doc<any>(this.meterId).collection(('meterdata'), ref=> ref.where("day", "==", day).limit(10)).valueChanges();
 this.pastweek = this.db.collection('meters').doc<any>(this.meterId).collection(('meterdata'), ref=> ref.orderBy("date", "desc").limit(7)).valueChanges();

 }

}

我已尝试关注Get field from Firestore document,但它对我不起作用。我收到一条错误消息,提示“'Observable' 类型上不存在属性 'then'”

【问题讨论】:

    标签: angular google-cloud-firestore angularfire2


    【解决方案1】:

    你可以让每个变量都成为可观察的,让数据流过你的组件:)

    首先,您从可观察的路由参数中获取当前 id,然后您将获得带有 id 的仪表 angularfire 集合。

    然后从这个id结合meter observable,就可以得到所有其他的值了。

    readonly meterDoc = this.route.paramMap.pipe(
      map((params) => params.get('id')),
      distinctUntilChanged(),
      map((id) => this.db.collection('meters').doc<Meter>(id)),
      shareReplay({ refCount: true, bufferSize: 1 })
    );
    
    readonly meter = this.meterDoc.pipe(
      map((meter) => meter.valueChanges())
    );
    
    readonly docMeter = combineLatest([
      this.meterDoc,
      this.meter
    ]);
    
    readonly dailydata = this.docMeter.pipe(
      switchMap(([ doc, meter ]) => doc.collection('dailydata').doc(meter.day).valueChanges())
    );
    
    readonly todayinweek = this.docMeter.pipe(
      switchMap(([ doc, meter ]) => doc.collection(
        'meterdata',
        ref => ref.where("day", "==", meter.day).limit(10)
      ).valueChanges())
    );
    
    readonly pastweek = this.meterDoc.pipe(
      switchMap((doc) => doc.collection(
        'meterdata',
        ref => ref.orderBy("date", "desc").limit(7)
      ).valueChanges())
    );
    

    未经测试的代码


    尽管您不愿意将所有内容都移动到流中,但您拥有的所有数据都是异步的。但幸运的是,您还有其他选择。您可以使用路由解析器来获取仪表,并在您的组件中读取:

    @Injectable({ providedIn: 'root' })
    export class MeterResolve implements Resolve<Meter> {
      resolve(route: ActivatedRouteSnapshot): Observable<Meter> {
        return this.db.collection('meters')
          .doc<Meter>(route.params.id)
          .valueChanges()
          .pipe(
            take(1)
          );
      }
    }
    

    将此添加到您的 id 路由:

    { route: 'meter/:id', component: MeterComponent, resolve: { meter: MeterResolve } } 
    

    然后您可以在您的组件中阅读此内容:

    readonly meterId = this.route.snapshot.params.id;
    readonly meter = this.route.snapshot.data.meter;
    readonly meterDoc = this.db.collection('meters').doc<Meter>(this.meterId);
    readonly dailydata = this.meterDoc.collection('dailydata').doc(this.meter.day).valueChanges();
    readonly todayinweek = this.meterDoc.collection(
        'meterdata',
        ref => ref.where("day", "==", this.meter.day).limit(10)
      ).valueChanges();
    readonly pastweek = this.meterDoc.collection(
        'meterdata',
        ref => ref.orderBy("date", "desc").limit(7)
      ).valueChanges();
    

    如果出于某种原因,您甚至不想使用解析器,您也可以在您的 ngOnInit 中进行订阅,然后从那里开始.. 但是.. 请不要:)(这是基于代码在你的问题中)

    ngOnInit() {
      this.meter.pipe(
        take(1)
      ).subscribe(({ day }) => {
        this.dailydata = this.db.collection('meters').doc<any>(this.meterId).collection('dailydata').doc(day).valueChanges();
        this.todayinweek = this.db.collection('meters').doc<any>(this.meterId).collection(('meterdata'), ref=> ref.where("day", "==", day).limit(10)).valueChanges();
        this.pastweek = this.db.collection('meters').doc<any>(this.meterId).collection(('meterdata'), ref=> ref.orderBy("date", "desc").limit(7)).valueChanges();  
      });
    }
    

    【讨论】:

    • 谢谢,但这对我的问题来说似乎有点压倒性,只是为了能够写出“meter.day”这一行。其他一切正常,我质疑 this.docMeter.pipe(switchMap... 正在添加到解决方案中。
    • @EzraButler 您的meter.day 来自可观察对象,因此您只能从可观察对象内部访问它。这意味着依赖于这个变量的所有东西也需要是可观察的,这就是上面的代码。您需要的每个数据作为流,您可以使用 async 管道在模板中访问这些数据
    • 我已经可以在我的模板中使用aysnc 访问它,没有问题。我希望能够将该字段用作变量来传递各种其他调用。我需要能够一次性获取该数据以供使用。我是否完全遗漏了一些非常明显的东西?
    • @EzraButler 你是 :) 异步管道也在使用 observable。但是,您可以先使用 subscribe 在组件内部获取值,然后为其他项目创建可观察对象,但对于 rxjs,这是非常糟糕的做法。另一种获得你想要的东西的方法是在你的路线中使用一个解决方案,它解决了你需要的“一天”。但是,如果另一个用户在您位于同一页面时更改了“日期”,它将不会为您更新,并且您将失去 firebase 的实时性。所以最好把所有东西都放在流中
    • @EzraButler 我会用更多方法更新我的答案
    猜你喜欢
    • 2018-06-04
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多