1

I have remote web api data like this:

[
    {
        "courseName": "Matematik",
        "contentsCount": 2,
        "createdDate": "2019/10/20"
    },
    {
        "courseName": "Matematik",
        "contentsCount": 1,
        "createdDate": "2019/10/16"
    },
    {
        "courseName": "Matematik",
        "contentsCount": 1,
        "createdDate": "2019/10/17"
    },
    {
        "courseName": "Matematik",
        "contentsCount": 2,
        "createdDate": "2019/10/22"
    },
    {
        "courseName": "Matematik",
        "contentsCount": 1,
        "createdDate": "2019/08/21"
    },
    {
        "courseName": "Türkçe",
        "contentsCount": 1,
        "createdDate": "2019/10/20"
    },
    {
        "courseName": "Türkçe",
        "contentsCount": 1,
        "createdDate": "2019/10/18"
    },
    {
        "courseName": "Türkçe",
        "contentsCount": 1,
        "createdDate": "2019/10/21"
    },
    {
        "courseName": "Türkçe",
        "contentsCount": 1,
        "createdDate": "2019/08/22"
    },
    {
        "courseName": "Türkçe",
        "contentsCount": 1,
        "createdDate": "2019/09/21"
    },
    {
        "courseName": "Türkçe",
        "contentsCount": 1,
        "createdDate": "2019/09/22"
    }
]

I want to group this data by createdDate and sum with contentsCount after getting data remotely.

I am getting data like this with Angular 8.

return this.repository.getData(`api/course/contents/report/${this.teacherId}`)
      .pipe(
        groupBy(x => x["createdDate"]),
      )
       .toPromise()
       .catch(error => { throw 'Data Loading Error' });

So how can I do this in RxJS pipe.

Thanks.

tcetin
  • 979
  • 1
  • 21
  • 48

2 Answers2

0

You can try like this:

  constructor() {
     var groupedData = this.groupByKey(this.data, "createdDate");

    Object.keys(groupedData).forEach(x => {
      this.res.push(
        {
          createdDate : x,
          contentsCount : (groupedData[x].map(y => y.contentsCount)).reduce(function(a, b) { return a + b; }, 0)
        }
      )
    });
  }

  groupByKey(data, key) {
    return data.reduce(function(rv, x) {
      (rv[x[key]] = rv[x[key]] || []).push(x);
      return rv;
    }, {});
  }

Working Demo

Adrita Sharma
  • 21,581
  • 10
  • 69
  • 79
  • please reference when you use part of another [answer](https://stackoverflow.com/a/34890276/4711754) – Andrew Allen Oct 22 '19 at 11:28
  • GroupBy should be with sum of "contentsCount".It should be new list like this: [{createdDate:xxx,contentsCount:yyy},...] – tcetin Oct 22 '19 at 11:29
  • 1
    @AndrewAllen I copied it from one of my projects. May be long time back I used it from the reference you mentioned – Adrita Sharma Oct 22 '19 at 11:32
  • @kodcu Check the modified answer and demo. Do you want like this? – Adrita Sharma Oct 22 '19 at 11:46
  • Thanks its correct also. But what about using in a pipe method? Expecting usage of like this https://rxjs-dev.firebaseapp.com/api/operators/groupBy – tcetin Oct 22 '19 at 18:14
0

If you want to group in RxJS pipe

first of all, define a method to groupBy (pass items and key to group):

In your service:

import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

export class SampleService {

  constructor(private http: HttpClient) { }

  public getCourses(): Promise<any> {
    return this.http.get(`api/course/contents/report/${this.teacherId}`).pipe(
      map(result => {
        return this.groupBy(result, "createdDate")
      })
    ).toPromise();
  }


private groupBy(value: Array<any>, field: string): Array<any> {
   const groupedObj = value.reduce((prev, cur) => {
   if (!prev[cur[field]]) {
     prev[cur[field]] = [cur];
   } else {
     prev[cur[field]].push(cur);
   }
   return prev;
  }, {});
  return Object.keys(groupedObj).map(key => ({ key, groupedItems: groupedObj[key], sum: this.sumOfContentsCount(groupedObj[key]) }));
}

private sumOfContentsCount(item) {
  let sum = 0;
  item.forEach(item => {
   sum += item.contentsCount;
  })
  return sum;
}

}

Then in your component:

  result: any;
  constructor(private sampleService: SampleService) {}

  ngOnInit(): void {
    this.sampleService.getCourses().then(result => {
      this.result = result;
    }).catch(error => {
      //Error
    })
  }

and finally in the Html :

 <div class="col-md-12 mt-5" *ngIf="this.result">
    <ul>
        <li *ngFor="let group of result">
            <div class="col-md-12">
                    Key Is :<span class="badge badge-primary">{{group.key}}</span> &nbsp; Sum is : <span class="badge badge-info">{{group.sum}}</span>
            </div>
            <div class="col-md-12">
                <table class="table table-sm table-bordered">
                    <tr *ngFor="let item of group.groupedItems">
                        <td>{{item.courseName}}</td>
                        <td>{{item.contentsCount}}</td>
                        <td>{{item.createdDate}}</td>
                    </tr>
                </table>
            </div>
        </li>
    </ul>
</div>
Abolfazl Roshanzamir
  • 12,730
  • 5
  • 63
  • 79