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

I a*_*bot 3 firebase typescript angular 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);
  }
Run Code Online (Sandbox Code Playgroud)

在组件内部,我需要该数据用于后续步骤,所以我这样做了-

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!";
      }

    });

  }
Run Code Online (Sandbox Code Playgroud)

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

Jak*_*ätt 6

如果您希望从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$;
}
Run Code Online (Sandbox Code Playgroud)

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

// 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;
    }
  }));
Run Code Online (Sandbox Code Playgroud)

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

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!';
      }
    }));
}
Run Code Online (Sandbox Code Playgroud)

请注意,直到您在this.user $上调用subscribe为止,用户将为null。或者在HTML中使用异步管道处理可观察对象上的subscribe和unsubscribe。

<div *ngIf="(user$ | async) as user">{{ user.email }}</div>
Run Code Online (Sandbox Code Playgroud)

尝试避免在您的html中对同一可观察的多次使用异步管道,而应将其设置为我上面(以用户身份)执行的本地html变量,以避免不必要的数据传递到db

有关命名约定的说明。Observable的变量名通常后缀“ $”,而其他变量(字符串,数字等)则不带有“ $”。