Javascript 如何从FirebaseListObservable映射和减少子值
我试图总结考试成绩,我的数据如下Javascript 如何从FirebaseListObservable映射和减少子值,javascript,angular,firebase,firebase-realtime-database,angularfire2,Javascript,Angular,Firebase,Firebase Realtime Database,Angularfire2,我试图总结考试成绩,我的数据如下 { testResult: { foo: {foo1: x}, {foo2: y} }, { bar: {bar1: z} let res = this._dbref.database.list('/bmzi-answers',{ query: { orderByKey: true, equalTo: id
{ testResult:
{ foo:
{foo1: x},
{foo2: y}
},
{ bar:
{bar1: z}
let res = this._dbref.database.list('/bmzi-answers',{
query: {
orderByKey: true,
equalTo: id
}
})
“foo”和“bar”是有意义的问题子类别,子节点包含问题ID和相应的分数。我需要按类别总结分数。我这样查询列表
{ testResult:
{ foo:
{foo1: x},
{foo2: y}
},
{ bar:
{bar1: z}
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等概念,但我对反应式Javascript、Angular2和AngularFire还不熟悉
请帮助并提前感谢您
编辑:
所有儿童都有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
}
}
}
您的查询使用orderByKey
和equalTo
获取可观察到的列表,该列表发出一个数组。如果键存在,查询将只返回包含单个对象的数组。将键合并到查询路径中会更简单,如下所示:
let res = this._dbref.database.list(`/bmzi-answers/${id}`);
此查询返回的可观察对象将是一个包含键的子项的数组(以AngularFire方式表示):
RxJSmap
运算符可用于将发出的数组转换为另一个值,并且可以使用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
前缀,则不需要过滤器,但您的问题无法说明是否存在这种情况。流会发出数据。一条可观测的河流就是一条小溪
例如:
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 a.reduce()
功能也可用,与es5阵列相同。reduce
功能。您可以对流执行与对数组相同的操作
数组是内存中的序列。流是随时间变化的序列
这就是为什么我们可以轻松地将数组转换为流。我们可以在每个发射之间设置间隔。etc这几乎解决了问题,但当我订阅res时,let score=res.subscribe(sum=>console.log(sum))
的值未定义,但仅第一次计算了分数。我如何保证在订阅res时还原完成?reduce是同步的,所以这不是问题所在。如果在map
操作符之前添加do((array)=>{console.log(JSON.stringify(array));})
,导致未定义的分数的第一个发出的数组值是什么?它是[{“$value”:3,$key”:“fitges1”},{“$value”:3,$key”:“fitges2”},{“$value”:3,$key”:“fitges3”}。我不知道是否合适,但是我会发布一个答案来显示代码。它应该是console.log(“score:+sum)
。score
变量保存subscription对象。这有助于理解“更大的图景”,并提醒我订阅转换后的observable对象非常感谢你,上帝也保佑你!