How to map and reduce child values from FirebaseListObservable

一笑奈何 提交于 2020-01-14 12:18:41

问题


I am trying to sum up test scores, my data looks like this

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

'foo' and 'bar' are meaningful subcategories of questions, child-nodes hold questionIDs and corresponding scores. I need to sum up scores ordered by categories. I query the list like this

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

and displaying the result with {{ res | async | json }} shows me, that the query works. I get something like

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

How can I reduce the values in my component logic, to get the sum of all questions labeled cat* ?

I understand concepts like filter / map / reduce, but I am new to Reactive Javascript, Angular2 and AngularFire.

Please help and thank you in advance!

Edit: All children have the cat prefix, this is part of the domain / the questionnaire. This code

  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;

produces this console output, the first time it's called:

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

and the second time this:

[]  
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 

回答1:


Your example output suggests the following data:

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

Your query uses orderByKey and equalTo to obtain a list observable that emits an array. Provided the key exists, the query will only ever return an array containing a single object. It would be simpler to incorporate the key in the query's path, like this:

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

The observable returned by this query will be an array containing the key's children (represented in the AngularFire way):

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

The RxJS map operator can be used to transform the emitted array to another value and the transformation can be performed using the Array.proptype functions with which you state you are familiar:

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)
    );

If all children have the cat prefix, the filter is not required, but your question doesn't make clear whether or not that's the case.




回答2:


A stream emits data. An observable is a stream.

For example:

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

This code creates an observable stream which emits 3 then 6 then 9

Now lets say we wanted to double those values:

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

Now the stream emits 6, 12, 18.

Finally we could do:

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

Now we can subscribe to stream1 or stream2 or both.

PS a .reduce() function is also available the same as the es5 Array.reduce function. You can do the same with streams as you can with Arrays.

An array is an in memory sequence. A stream is a sequence over time.

This is why we can easily convert an array to a stream. We could put intervals between each emit. etc



来源:https://stackoverflow.com/questions/41044645/how-to-map-and-reduce-child-values-from-firebaselistobservable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!