如何映射和减少 Firebase List Observable 中的 child 值

How to map and reduce child values from FirebaseListObservable

我正在尝试总结考试成绩,我的数据是这样的

   { testResult: 
      { foo:
         {foo1: x},
         {foo2: y}
      },
      { bar:
         {bar1: z}

'foo' 和 'bar' 是有意义的问题子类别,child-nodes 包含问题 ID 和相应的分数。我需要总结按类别排序的分数。我这样查询列表

let res = this._dbref.database.list('/bmzi-answers',{
      query: {
        orderByKey: true,
        equalTo: id
      }
    })

并用 {{ res | async | json }} 显示结果告诉我,查询有效。我得到类似

的东西
[{"cat1":3, "cat2":3, "cat3":3, "$key":"cat"}]

如何减少组件逻辑中的值,以获得所有标记为 cat* 的问题的总和?

我了解 filter/map/reduce 等概念,但我是 Reactive Javascript、Angular2 和 AngularFire 的新手。

请提前帮忙,谢谢!

编辑: 所有 children 都有 cat 前缀,这是域/问卷的一部分。此代码

  let res = this.dbRef.database.list(`/bmzi-answers/${id}`)
                  .do((array) => { console.log(JSON.stringify(array)); })
                  .map((array) => array
                      .reduce((acc, element) => acc + element.$value, 0)
            )
  let score = res.subscribe(sum => {
                  console.log("score: " + sum)
              });
  return score;

第一次调用时产生此控制台输出:

[
    { "$key": "cat1", "$value": 3 },
    { "$key": "cat2", "$value": 3 },
    { "$key": "cat3", "$value": 3 }
]
score: [object Object]

这是第二次:

[]  
score: undefined  
[{"$value":3,"$key":"fitges1"}]
score: undefined  
[{"$value":3,"$key":"fitges1"},{"$value":3,"$key":"fitges2"}]
score: undefined 
[{"$value":3,"$key":"fitges1"},{"$value":3,"$key":"fitges2"},{"$value":3,"$key":"fitges3"}]  
score: undefined 

您的示例输出建议以下数据:

{
    "bmzi-answers": {
        "cat": {
            "cat1": 3,
            "cat2": 3,
            "cat3": 3
        }
    }
}

您的查询使用 orderByKeyequalTo 来获取发出数组的可观察列表。如果键存在,查询只会 return 一个包含单个 object 的数组。将键合并到查询路径中会更简单,如下所示:

let res = this._dbref.database.list(`/bmzi-answers/${id}`);

此查询所观察到的 return 将是一个包含键 children 的数组(以 AngularFire 方式表示):

[
    { "$key": "cat1", "$value": 3 },
    { "$key": "cat2", "$value": 3 },
    { "$key": "cat3", "$value": 3 }
]

RxJS map 运算符可用于将发出的数组转换为另一个值,并且可以使用您声明熟悉的 Array.proptype 函数执行转换:

let id = "cat";
let regExp = new RegExp(`${id}\d+`);
let res = this._dbref.database
    .list(`/bmzi-answers/${id}`)
    .map((array) => array
        .filter((element) => regExp.test(element.$key))
        .reduce((acc, element) => acc + element.$value, 0)
    );

如果所有 children 都有 cat 前缀,则不需要 filter,但您的问题并不清楚是否是这种情况。

流发出数据。一个可观察对象是一个流。

例如:

let stream = Rx.Observable.from([3,6,9]) 

此代码创建一个可观察流,它发出 3 然后 6 然后 9

现在假设我们想将这些值加倍:

let stream = Rx.Observable.from([3,6,9]).map((value) => {return value*2})

现在流发出 6、12、18。

我们终于可以做到了:

let stream1 = Rx.Observable.from([3,6,9])
let stream2 = stream1.map((value) => {return value*2})

现在我们可以订阅 stream1 或 stream2 或两者。

PS 一个 .reduce() 函数也可用,与 es5 Array.reduce 函数一样。您可以对流执行与对数组相同的操作。

数组是内存序列。流是随时间变化的序列。

这就是我们可以轻松地将数组转换为流的原因。我们可以在每次发射之间设置间隔。等等