如何映射和减少FirebaseListObservable中的子值

时间:2016-12-08 16:48:22

标签: javascript angular firebase firebase-realtime-database angularfire2

我想总结测试成绩,我的数据看起来像这样

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

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

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的新手。

请提前帮助并表示感谢!

编辑: 所有孩子都有猫前缀,这是域/问卷的一部分。这段代码

  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 

2 个答案:

答案 0 :(得分:2)

您的示例输出显示以下数据:

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

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

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

此查询返回的observable将是一个包含键的子项的数组(以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)
    );

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

答案 1 :(得分:1)

流会发出数据。可观察的是一个流。

例如:

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函数相同。您可以使用Arrays对流进行相同的操作。

数组是内存序列。流是一段时间的序列。

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