angular - 如何从 Angular 7 中的 Firestore 查询中获取数据的 Observable?

标签 angular typescript firebase google-cloud-firestore

我的服务中有一个方法,我试图在其中返回一个 User 对象的 Observable。这是我的代码 -

 constructor(private firestore: AngularFirestore,
    private db: AngularFireDatabase) { }

 /**
   * get user with given email, if not return null
   * 
   * @param email email to fetch
   */
  getUserByEmail(email: string): Observable<User> {

    var user: User;

    let userRef = this.firestore.collection("users").ref.where('email', '==', email);

    userRef.get().then(res => res.forEach(userDoc => {

      user = userDoc[0].data() as User; // since email IDs are unique, I want the 0th element.
      user.id = userDoc[0].id;

      console.log(user); // has the data

      // return user; // doesn't work, not the right thing

    }));

    console.log(user); // undefined, since call is async

    return of(user);
  }

在组件内部,我想要下一步的数据,所以我这样做了 -

checkEmail() {

    var user$: User

    this.us.getUserByEmail(this.existingUserForm.value.email).subscribe(user => {

      console.log(user);

      if (user) {

          this.msg$ = "success";
          // next steps
      }
      else {
        this.msg$ = "User with this email does not exist!";
      }

    });

  }

我不确定如何从我的服务返回一个可观察对象,以便我可以在我的组件中使用数据。这是做我想做的事情的正确方法吗?

最佳答案

如果您想要从 Firestore 中观察到,您需要在 AngularFirestoreCollection 上返回 .valueChanges()。 阅读此文档以供引用:https://github.com/angular/angularfire2/blob/master/docs/firestore/querying-collections.md .

在您的服务中:(为了清楚起见,我已经声明了 collection 和 user$ 变量)。

getUserByEmail(email: string): Observable<User> {
const collection = this.firestore.collection<User>('users', ref => ref.where('email', '==', email))
const user$ = collection
  .valueChanges()
  .pipe(
    map(users => {
      const user = users[0];
      console.log(user);
      return user;
    })
  );

return user$;
}

如果您还需要用户的 ID,则需要使用 snapshotChanges()。有时,在保存到 firestore 以避免使用 snapshotChanges 时,维护用户数据的 ID 更容易(在我看来)。

// Query the users by a specific email and return the first User with ID added    
return this.firestore.collection<User>('users', ref => ref.where('email', 
'==', email))
  .snapshotChanges()
  .pipe(map(users => {
    const user = users[0];
    if (user) {
      const data = user.payload.doc.data() as User;
      const id = user.payload.doc.id;
      return { id, ...data };
    }
    else {
      return null;
    }
  }));

在您的组件代码中,您可以通过以下方式调用它

checkEmail() {
this.user$ = this.us.getUserByEmail('email@gmail.com')
  .pipe(
    tap(user => {
      if (user) {
        this.msg = 'success';
      } else {
        this.msg = 'User with this email does not exist!';
      }
    }));
}

请注意,在您调用 this.user$ 上的订阅之前,用户将为空,或者在您的 html 中使用处理订阅和取消订阅的异步管道。

<div *ngIf="(user$ | async) as user">{{ user.email }}</div>

尽量避免在您的 html 中对同一个可观察对象多次使用异步管道,而是将其设置为我在上面(作为用户)所做的本地 html 变量,以避免不必要的数据访问 db

关于命名约定的说明。 Observables 的变量名通常以“$”为后缀,而其他(字符串、数字等)则没有“$”。

关于angular - 如何从 Angular 7 中的 Firestore 查询中获取数据的 Observable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54002758/

相关文章:

Angular Material Table - 异步数据源的问题

typescript - 找不到名称 'describe'。您需要为测试运行器安装类型定义吗?

android - 火力地堡 10.0。 : InternalFirebaseAuth. FIREBASE_AUTH_API 在此设备上不可用

javascript - Aurelia 中的导航附加 "?id=5"而不是 "/5"

html - 用蓝色突出显示 div 中的文本

javascript - NodeJS从缓冲区解码字符串返回多行字符串

javascript - 如何启动 Firebase Analytics 在 Web 上工作?

android - 如何有条件地在 ionic 4 中设置根页面?

html - 如何仅在选定元素上动态应用 CSS [Angular]

angular - 在带 Angular 选择中加载默认选项