0

here is what iam trying to achieve, i want to groupBy product_category in Array JSON but my array JSON is nested, which looks like this :

[
    {
        "result": "success",
        "data": [
            {
                "product_id": 17,
                "product_name": "KLO-101",
                "parent_category": "Juicer"
            },
            {
                "product_id": 42,
                "product_name": "CRO-528",
                "parent_category": "Vacuum Cleaner"
            },
            {
                "product_id": 15,
                "product_name": "KLC-127",
                "parent_category": "Juicer"
            },
            {
                "product_id": 41,
                "product_name": "CRO-3120-WD",
                "parent_category": "Vacuum Cleaner"
            }
        ]
    }
]

what the json i want to build is, below is JSON illustration that i made write manually :

[{
    'Vacuum Cleaner' : 
           [{
                "product_id": 41,
                "product_name": "CRO-3120-WD",
                "parent_category": "Vacuum Cleaner"
            },
            {
                "product_id": 42,
                "product_name": "CRO-528",
                "parent_category": "Vacuum Cleaner"
            }],
   'Juicer' : 
            [{
                "product_id": 17,
                "product_name": "KLO-101",
                "parent_category": "Juicer"
                 },
            {
                "product_id": 15,
                "product_name": "KLC-127",
                "parent_category": "Juicer"
            }]
}]

from what i read, in stackoverflow somewhere its written that JSON data can be grouped with using map().groupBy() which is in my code and it looks like this :

app.service.ts :

getProductService(): Observable<any> {
    return this.http
        .post(global.server + "/product", this.options)
        .map(a=> a.json().data)
        .groupBy(
            a=>a.parent_category,
            a=>a
        )
        .catch(this.handleError);
}

and here is my app.component.ts :

  getProduct() {
    this.appService.getProductService().subscribe(
      result => {
        console.log(result);
        this.dataProduct = result[0].data;
      },
      error => this.errorMessage = <any>error
    );
  }

but i get an error, 'a is undefined' how to use .groupBy() properly? angular version that i use is angular 4

UPDATE!!!

here is my code after i updated with martin answer, but still i can't figure it out, since i have to pull the JSON data from REST API, the code won't detect the 'parent_category', below is my code

app.component.ts

dataProduct : any;

      getProduct() {
        this.appService.getProductService().subscribe(
          result => {
            this.dataProduct = result[0].data;
          },
          error => this.errorMessage = <any>error
        );

        Observable.of(this.dataProduct)
          .mergeMap(array => array) // unpack into single emissionns (or mergeAll() but it's broken in RxJS 5.4)
          .groupBy(item => item.parent_category)
          .mergeMap(observable => observable
            .toArray()
            .map(results => (this.dataProduct = { [results[0].parent_category]: results }))
          )
          .toArray()
          .subscribe(console.log);

          console.log(JSON.stringify(this.dataProduct));
      }

i got error

[ts] Property 'parent_category' does not exist on type '{}'

enter image description here

Ke Vin
  • 3,478
  • 11
  • 60
  • 91

3 Answers3

0

In angular 1 this is the way i do

var inputdata = [
{
    "result": "success",
    "data": [
        {
            "product_id": 17,
            "product_name": "KLO-101",
            "parent_category": "Juicer"
        },
        {
            "product_id": 42,
            "product_name": "CRO-528",
            "parent_category": "Vacuum Cleaner"
        },
        {
            "product_id": 15,
            "product_name": "KLC-127",
            "parent_category": "Juicer"
        },
        {
            "product_id": 41,
            "product_name": "CRO-3120-WD",
            "parent_category": "Vacuum Cleaner"
        }
    ]
}];

var grouped = _(inputdata[0].data).groupBy(function (d) {
    return d.parent_category;
});

var finalArray = _.mapObject(grouped, function (value, key) {
    return value;
});
Sai Reddy
  • 67
  • 5
0

groupBy is an RxJS operator that emits Observables. In other words it returns an Observable emitting other Observables (so called "higher-order Observable"). It would be easier for you to use just map() and transform data there but if you want to go with groupBy you'll need to do some adjustments to make sure the inner Observable completes before you pass it to the resulting object:

const data = [
    {
        "product_id": 17,
        "product_name": "KLO-101",
        "parent_category": "Juicer"
    },
    {
        "product_id": 42,
        "product_name": "CRO-528",
        "parent_category": "Vacuum Cleaner"
    },
    {
        "product_id": 15,
        "product_name": "KLC-127",
        "parent_category": "Juicer"
    },
    {
        "product_id": 41,
        "product_name": "CRO-3120-WD",
        "parent_category": "Vacuum Cleaner"
    }
];

Observable.of(data)
    .mergeMap(array => array) // unpack into single emissionns (or mergeAll() but it's broken in RxJS 5.4)
    .groupBy(item => item.parent_category)
    .mergeMap(observable => observable
        .toArray()
        .map(results => ({ [results[0].parent_category] : results }))
    )
    .toArray()
    .subscribe(console.log);

Prints:

[ { Juicer: [ { product_id: 17,
       product_name: 'KLO-101',
       parent_category: 'Juicer' },
     { product_id: 15,
       product_name: 'KLC-127',
       parent_category: 'Juicer' } ] },
  { 'Vacuum Cleaner': [ { product_id: 42,
       product_name: 'CRO-528',
       parent_category: 'Vacuum Cleaner' },
     { product_id: 41,
       product_name: 'CRO-3120-WD',
       parent_category: 'Vacuum Cleaner' } ] 
} ]
martin
  • 93,354
  • 25
  • 191
  • 226
  • i am sorry, can you be more specific? where should i put the Observeable.of code? in my app.component.ts or app.service.ts? i should put it inside the this.http.post().map and continue here right? – Ke Vin Oct 11 '17 at 09:11
  • `Observable.of(data)` is instead of your `this.http.post(global.server + "/product", this.options).map(a=> a.json().data)` – martin Oct 11 '17 at 09:12
  • hi martin, how do i print the data in HTML where should i set the variable? i usually print the data in HTML is set the value into variable ex : this.dataTest = result[0].data – Ke Vin Oct 12 '17 at 03:43
  • @KeVin I have no idea how you want to print it in you HTML so I can't help you with it. – martin Oct 12 '17 at 09:37
  • i just want to print the json data just like this {{ dataTest | json }} and can you help me with the error? i updated my question for the error i got with following your code – Ke Vin Oct 13 '17 at 02:30
  • If you want have proper types or interfaces you can use `item['parent_category']` notation. – martin Oct 13 '17 at 07:22
0

i think i have to implement lodash since i really confuse about observeable way, i really can't understand it, so i decided to use lodash way, it's so simple, so here is my code how to group the JSON data properly. i have to import lodash which is already include in my project, if you dont have lodash in your node_modules, you have to npm install it

import * as _ from 'lodash';

  getProduct() {
    this.appService.getProductService().subscribe(
      result => {
        this.dataTest = result;

        let datas = this.dataTest;

        this.dataProduct = _(datas)
        .groupBy(data => data.parent_category)
        .map((datas, category) => ({ category, datas }))
        .value();

      },
      error => this.errorMessage = <any>error
    );

and i just need to loop the JSON data inside "datas" with *ngFor in HTML

Ke Vin
  • 3,478
  • 11
  • 60
  • 91
  • Hey, found this https://stackoverflow.com/questions/37771855/chaining-observables-in-rxjs. works fine. – Murwa Mar 07 '19 at 23:29