【问题标题】:An observable object of observable arrays?可观察数组的可观察对象?
【发布时间】:2019-09-09 08:47:56
【问题描述】:

我有一个 Firestore 文档,它有两个属性,它们都是 Firestore 数据库中其他位置的不同 <Game>{} 对象的 Id 数组。

我有什么方法可以创建一个 observable 流式传输一个对象,该对象包含两个单独的项目数组,这些 id 代表的项目?

我认为没有办法只拥有一个单一的对象流,因为(一旦我订阅)我不知道哪个项目属于哪个数组,因为数组大小不是恒定的。

我是 observables 和 rxjs 的新手,并且经常阅读有关不同运算符的信息,但我有点卡在这里,如果找不到解决方案,我正在考虑重组我的数据。

现在,我的服务类中有类似的东西,但是当我订阅该功能时,它并没有像我预期的那样工作。

  getPlayerGames(uid: string) {
    return this._db.doc<PlayerGameSession>(`users/${uid}/mygamesession/games`).valueChanges().pipe(
      map(gameObj => {
        let combined1;
        let combined2;

        if (gameObj.prop1) {
          const prop1Streams = gameObj.prop1.map(
            gameId => this._db.doc<Game>(`games/${gameId}`).valueChanges()
          );

          combined1 = combineLatest(...prop1Streams);
        }

        if (gameObj.prop2) {
          const prop2Streams = gameObj.prop2.map(
            gameId => this._db.doc<Game>(`games/${gameId}`).valueChanges()
          );

          combined2 = combineLatest(...prop2Streams);
        }

        return combineLatest(combined1, combined2);

      }),
      switchMap(([c1, c2]) => of({ c1: c1, c2: c2 }))
    );
  }

【问题讨论】:

    标签: angular rxjs google-cloud-firestore observable


    【解决方案1】:

    如果你想返回一个包含两个数组的对象的 observable,你将返回一个 observable 对象的 observable 对象,该对象具有两个属性,你需要将数组 observables 组合起来,如下例所示:

    const v1 = new BehaviorSubject('1')
    const v2 = new BehaviorSubject('2')
    const v3 = new BehaviorSubject('3')
    const v4 = new BehaviorSubject('4')
    
    const combined1 = combineLatest(v1, v2)
    const combined2 = combineLatest(v3, v4)
    
    const combined3 = combineLatest(combined1, combined2)
    
    combined3
      .pipe(switchMap(([c1, c2]) => of({c1: c1, c2: c2})))
      .subscribe(console.log)
    

    在这个例子中,我将四个 observable 组合成两个数组,然后将这些数组组合成一个组合对象

    试试这个代码:

    getPlayerGames(uid: string) {
        return this._db.doc<PlayerGameSession>(`users/${uid}/mygamesession/games`).valueChanges().pipe(
      switchMap(gameObj => {
        let combined1 = of([]);
        let combined2 = of([]);;
    
        if (gameObj.prop1) {
          const prop1Streams = gameObj.prop1.map(
            gameId => this._db.doc<Game>(`games/${gameId}`).valueChanges()
          );
    
          combined1 = combineLatest(...prop1Streams);
        }
    
        if (gameObj.prop2) {
          const prop2Streams = gameObj.prop2.map(
            gameId => this._db.doc<Game>(`games/${gameId}`).valueChanges()
          );
    
          combined2 = combineLatest(...prop2Streams);
        }
    
        return combineLatest(combined1, combined2)
           .pipe(switchMap(([c1, c2]) => of({c1: c1, c2: c2}))
    
      })
    );
    

    }

    【讨论】:

    • 我更新了上面的代码示例。我在switchMap() arg of [c1, c2] 上得到Type 'OperatorFunction&lt;{}, {}&gt;' is not an array type.ts(2461)
    • 更新了我的答案,试试这个代码。这是使用 switchMap 的有效方法我一直都这样使用它,尝试检查您的导入
    • 感谢更新。现在的问题是我不能在最后一个combineLatest 上使用.pipe(),因为那时它是 OperatorFunction 类型而不是 Observable,所以没有 pipe()。我知道我们已经接近解决方案并且可能遗漏了一些非常明显的东西,但现在我明白了:Property 'pipe' does not exist on type 'OperatorFunction&lt;{}, {}&gt;'.ts(2339)
    • 你是从正确的文件夹导入 combineLatest 吗?你应该从 rxjs 而不是 rxjs/operators 导入它,请检查
    • 啊,是的,这就是问题所在。谢谢您的帮助!这里还有一个问题,处理两个导入 stackoverflow.com/questions/52950090/… 之间的差异。再次感谢,我有一些阅读要做:)
    猜你喜欢
    • 2012-04-20
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    相关资源
    最近更新 更多