1

这个 js reduce 可以很好地处理查询结果:

function toc(current) {
  return {....};
};
function getToc(data) {
  return = data.reduce((a, c) => Object.assign(a, {[c.id]: toc(c)}), {});
};

const query = db.collection(normCollection)
.where('a_id', '==', a_id )
.where('year', '==', year) 
.orderBy("id");
subscriptionNorm = collectionData(query, "id")
.subscribe(data => console.log(getToc(data)));

但是当我使用 RxJs reduce 时,它​​停止工作。它与流结束有关,但是......但我不明白 RxFire / RxJs 如何处理流式 Firestore 查询结果:

...
subscriptionNorm = collectionData(query, "id")
.pipe(reduce((a, c) => Object.assign(a, {[c.id]: toc(c)}), {}))
.subscribe(data => console.log(data));

更新这个工作正常,但是......:

...
subscriptionNorm = collectionData(query, "id")
.pipe(
  map(v => v.reduce((a, c) => 
    Object.assign(a, {[c.id]: toc(c)}), {})
  ),
)
.subscribe(data => console.log(data));
4

1 回答 1

2

您对 rxjs reduce 运算符的假设是正确的。

“在源 Observable 上应用累加器函数,并在源完成时返回累积的结果” - 来自文档,请参见此处:RxJS reduce docs

在您的情况下,源将无法完成,因为 Firestore 就是这样工作的,它在没有完成的情况下无休止地运行,直到发生错误或您手动取消订阅。

举个粗略的例子,你可以take(1)在管道中使用操作符,它会在发出 1 个事件后完成源 Observable,因此它reduce会起作用,但它会扼杀 Firestore Observable 背后的主要思想。

这是您可以使用 rxjsreduce运算符的方式:

subscriptionNorm = collectionData(query, "id").pipe(
  switchMap(data => from(data).pipe(
    reduce((a, c) => Object.assign(a, { [c.id]: toc(c) }), {})
  )),
).subscribe(data => console.log(data));

这是可能的,因为我正在切换到from(data)内部 Observable 将完成,因此reduce操作员将按您的意愿工作。

但是,老实说,这是一个矫枉过正,你可以简单地保持你已经实施的方式

subscriptionNorm = collectionData(query, "id").pipe(
  map(data => data.reduce((a, c) => Object.assign(a, { [c.id]: toc(c) }), {}))),
).subscribe(data => console.log(data));
于 2020-09-17T11:15:50.957 回答